Sign in to follow this  
Followers 0
FrankNatoli

MX Component C# Samples Missing

5 posts in this topic

Downloaded MX Component v4.04 seven day trial from Mitsubishi website. C# samples not present, see folder list below. Documentation bundled with MX Component mentions only languages below, but MX Component Programming Manual also mentions C#. One other query on this forum asked about C# samples, and user was directed to programming manual but not to samples. Anyone know why C# samples are not provided? Thanks. Directory of C:\MELSEC\Act\Samples 07/22/2015 12:25 PM <DIR> . 07/22/2015 12:25 PM <DIR> .. 07/22/2015 12:25 PM <DIR> AccessVBA 07/22/2015 12:25 PM <DIR> ExcelVBA 07/22/2015 12:25 PM <DIR> GppW 07/22/2015 12:25 PM <DIR> Vb.NET 07/22/2015 12:25 PM <DIR> VBScript 07/22/2015 12:25 PM <DIR> Vc 07/22/2015 12:25 PM <DIR> Vc.NET

Share this post


Link to post
Share on other sites
I am interested in C# examples for Mitsubishi PLC as well. Read in one forum that this language is not popular among PLC programmers. Several years ago I looked for a project to communicate between PC and Schneider PLC. The only example I found was written for Visual Basic.

Share this post


Link to post
Share on other sites
We used to use MX Component but quickly found OPC to be much more reliable. Below is code we use to use. May or may not be of use. Regards // --------------------------------------------------------------------------- // Date/Time: 28/06/2005 11:54 // Solution Name: MXWrapper // Project Name: MXWrapper // Project Item Name: MXWrapper.cs // Project Item Kind: Code // Purpose: C# Wrapper for the MX COM Component // --------------------------------------------------------------------------- using System; using System.Collections; using System.Windows.Forms; using System.Data; using System.Diagnostics; using System.Timers; namespace DCN.MXWrapper { /// <summary>The PLC Device Types.</summary> public enum DType { X,Y,M,S,TN,CN,D,R,V,Z,Missing } /// <summary>Available PLC Status Settings.</summary> public enum PLCStatus { Run = 0, Stop = 1, Pause = 2 } public delegate void DeviceTriggerHandler(string sDevice, int lData); public delegate void DataPollingHandler(int machine); /// <summary> /// C# Wrapper for the MX COM Component. /// </summary> public class MXWrapperClass { /// <summary> /// Device events /// </summary> public event DeviceTriggerHandler DeviceTrigger; public event DataPollingHandler PollDevice; /// <summary> /// Timer to generate the polling interval /// </summary> private System.Timers.Timer PollTimer = new System.Timers.Timer(); /// <summary> /// The PLC COM component object /// </summary> ACTMULTILib.ActEasyIFClass PLC; private bool m_Connected = false; string[] statusDevice; int[] statusData; public int machine; /// <summary> /// MXWrapper Constructor /// </summary> public MXWrapperClass() { // Create the MX Component Object PLC = new ACTMULTILib.ActEasyIFClass(); // Assign the delegates to the events PLC.OnDeviceStatus +=new ACTMULTILib._IActEasyIFEvents_OnDeviceStatusEventHandler(PLC_OnDeviceStatus); PollTimer.Elapsed += new ElapsedEventHandler(PollTimer_Tick); } /// <summary> /// The Logical station Number used in /// the MX Component Communication Setup Utility. /// </summary> public int LogicalStationNumber { set { PLC.ActLogicalStationNumber = value; } } /// <summary> /// Convert a numeric value to a hex string. /// </summary> /// <param name="numericValue"> /// the numeric value to convert</param> /// <returns> /// the hex string</returns> public static string Hex(int numericValue) { return "0x" + numericValue.ToString("x"); } /// <summary> /// Starts the polling event only if there is already an interval set /// </summary> public void StartDataPoll() { if (PollTimer.Interval > 0) { PollTimer.Start(); } } /// <summary> /// Starts the polling event. /// </summary> /// <param name="tickInterval"> /// The number of milli-seconds interval</param> public void StartDataPoll(int tickInterval) { PollTimer.Interval = tickInterval; PollTimer.Start(); } /// <summary> /// Starts the polling event. /// </summary> /// <param name="tickInterval"> /// The number of seconds interval</param> /// <param name="IntervalUnits">Number of milliseconds in the interval</param> public void StartDataPoll(int tickInterval, int IntervalUnits) { PollTimer.Interval = tickInterval * IntervalUnits; PollTimer.Start(); } /// <summary> /// Stops the polling event. /// </summary> public void StopDataPoll() { PollTimer.Stop(); } /// <summary> /// The polling event handler. /// </summary> private void PollTimer_Tick(object sender, ElapsedEventArgs e) { //Critical section - although we want to (roughly) poll every second //we shouldn't start a new poll before the existing one is complete. lock(this) { PollTimer.Enabled = false; // Generate the PollDevice event PollDevice(machine); PollTimer.Enabled = true; } } /// <summary> /// Sets the device names that will be monitored for the trigger. /// </summary> /// <param name="deviceList"> /// The devices to monitor</param> public void SetDeviceStatusNames(params string[] deviceList) { statusDevice = deviceList; } /// <summary> /// Sets the devices trigger values, /// any one will trigger the status event. /// </summary> /// <param name="valueList"> /// The trigger values</param> public void SetDeviceStatusValues(params int[] valueList) { statusData = valueList; } /// <summary> /// Start the trigger monitor. /// </summary> /// <param name="monitorCycle"> /// Number of seconds between trigger cycles</param> public void StartTrigger(int monitorCycle) { string deviceString = String.Join("\n", statusDevice); PLC.EntryDeviceStatus(deviceString, statusDevice.Length, monitorCycle, ref statusData[0]); } /// <summary> /// Stop the trigger monitor /// </summary> public void StopTrigger() { PLC.FreeDeviceStatus(); } /// <summary> /// The device status event. /// </summary> /// <param name="sDevice"> /// The triggering device</param> /// <param name="lData"> /// The value that caused the trigger</param> /// <param name="lReturnCode"> /// The returncode</param> public void PLC_OnDeviceStatus(string sDevice, int lData, int lReturnCode) { Debug.WriteLine("On Device Event: " + sDevice + ", " + lData.ToString() + ", "); DeviceTrigger(sDevice, lData); } /// <summary> /// Opens the connection to the PLC. /// </summary> /// <returns>the status of the operation, 0 if successful</returns> public int Connect() { // Try to establish connection int connectStatus = PLC.Open(); // If there is a problem opening the connection, // then make sure it is closed if (connectStatus == 0) { m_Connected = true; } else { PLC.Close(); m_Connected = false; } return connectStatus; } /// <summary> /// Closes the connection to the PLC. /// </summary> /// <returns>the status of the operation, 0 if successful</returns> public int Disconnect() { StopTrigger(); // Try to close connection int closeStatus = PLC.Close(); // The connection will always be closed even if there is no PLC m_Connected = false; return closeStatus; } /// <summary> /// Returns the device names as an array /// </summary> /// <param name="devices"> /// The PLCdevice array from which to get the names</param> /// <returns> /// The array of device names</returns> public string[] GetDeviceNames(PLCDevice[] devices) { string deviceString = string.Empty; // Create a string of devices names, delimited by newlines foreach (PLCDevice currentDevice in devices) { deviceString += currentDevice.DeviceName + "\n"; } // Remove the last newline deviceString = deviceString.TrimEnd('\n'); // Return the string converted into a string array return deviceString.Split('\n'); } /// <summary> /// Convert a string to a Int16 arraylist. /// </summary> /// <param name="Reversed"> /// true if the bytes should be reversed</param> /// <param name="ASCIIString"> /// the original string</param> /// <returns>the array of integers</returns> public static int[] StringTo16BitRegisters(bool Reversed, string ASCIIString) { string stringToConvert = ASCIIString; int Stringlength = stringToConvert.Length; //Even up the String length with a space if (Stringlength % 2 == 1) { stringToConvert += " "; Stringlength = stringToConvert.Length; } int ArrayLength = Stringlength / 2; int[] Int16Array = new int[ArrayLength]; for (int charIndex = 0; charIndex < ArrayLength ; charIndex = charIndex + 1) { int lByte = Convert.ToInt32(stringToConvert[(charIndex * 2) + 1]); int hByte = Convert.ToInt32(stringToConvert[charIndex * 2]); if (Reversed) { Int16Array[charIndex] = hByte + lByte * 0x100; } else { Int16Array[charIndex] = lByte + hByte * 0x100; } } return Int16Array; } public string Int16RegistersToString(bool Reversed, int[] dreg_array,int MaxLength) { string ASCIIString = string.Empty; int Count = 0; try { foreach (int dreg in dreg_array) { if(Count >= MaxLength) break; Count++; int lByte = dreg & 0xff; int hByte = dreg / 0x100; // If the input numbers need to be reversed if (Reversed) { // Low Byte ASCIIString += Convert.ToChar(lByte); // High Byte ASCIIString += Convert.ToChar(hByte); } else { // High Byte ASCIIString += Convert.ToChar(hByte); // Low Byte ASCIIString += Convert.ToChar(lByte); } } } catch (Exception err) { MessageBox.Show("IntToASCIIConversion Error: " + err.Message); } return ASCIIString.TrimEnd(); } public string Int16RegistersToStringWithOffset(bool Reversed, int[] dreg_array,int MaxLength,int Offset) { string ASCIIString = string.Empty; try { for (int x = Offset;x < Offset+MaxLength;x++) { int lByte = dreg_array[x] & 0xff; int hByte = dreg_array[x] / 0x100; // If the input numbers need to be reversed if (Reversed) { // Low Byte ASCIIString += Convert.ToChar(lByte); // High Byte ASCIIString += Convert.ToChar(hByte); } else { // High Byte ASCIIString += Convert.ToChar(hByte); // Low Byte ASCIIString += Convert.ToChar(lByte); } } } catch (Exception err) { MessageBox.Show("IntToASCIIConversion Error: " + err.Message); } return ASCIIString.TrimEnd(); } /// <summary> /// Converts a string to a fixed length Int16 array. /// </summary> /// <param name="numberString"> /// The string to convert</param> /// <param name="noOfRegisters"> /// The number of Int16 values for the array</param> /// <param name="Reversed">true if the the ligh/low bytes should be reversed</param> /// <returns>The converted array</returns> private int[] StringToRegisters(string numberString, int noOfRegisters, bool Reversed) { int[] Int16array = new int[noOfRegisters]; Int16array = StringTo16BitRegisters(Reversed, numberString); //Insert spaces (0x2020) into array items not used for (int arrayIndex = noOfRegisters - 1; arrayIndex >= 0; arrayIndex--) { if (Int16array[arrayIndex] != 0) { break; } Int16array[arrayIndex] = 0x2020; } return Int16array; } /// <summary> /// Writes a block of text to the PLC. /// </summary> /// <param name="deviceID"> /// The ID of the block of D registers to write</param> /// <param name="fieldText"> /// The text to write (max 30 characters)</param> public void WriteTextToPLC(PLCDevice TextDevice, string fieldText, int maxSize) { int[] BlockData = StringTo16BitRegisters(true, fieldText.PadRight(maxSize)); WriteDeviceBlock(TextDevice, maxSize / 2, BlockData); } /// <summary> /// Reads a block of text from the PLC. /// </summary> /// <param name="deviceID"> /// The ID of the block of D registers to write</param> /// <param name="maxSize">The Size of the text to return</param> /// <returns>The PLC Text</returns> public string ReadTextFromPLC(PLCDevice TextDevice, int maxSize) { int[] BlockData; ReadDeviceBlock(TextDevice, (maxSize + 1) / 2, out BlockData); string Text = Int16RegistersToString(true, BlockData,BlockData.Length); if (Text.Length > maxSize) { Text = Text.Substring(0, maxSize - 1); } return Text; } /// <summary> /// Convert 2 16 Bit Registers to a single 32 bit register /// </summary> /// <param name="hNumber">High Register value</param> /// <param name="lNumber">Low Register value</param> /// <returns>32Bit Register Value</returns> public static System.Int32 ConvertTwo16bitTo32Bit(int hNumber, int lNumber) { //JF: Fixed 09/03/06 System.Int32 Result; int hValue; int lValue; // Make Sure the values are only 16 Bits in size hValue = hNumber & 0xffff; lValue = lNumber & 0xffff; // Create 32bit value Result = (((System.Int32)hValue) << 16) + lValue; return Result; } /// <summary> /// Retrieves the PLC CPU type. /// </summary> /// <param name="CPUType"> /// The PLC CPU type name</param> /// <param name="CPUCode"> /// The PLC CPU ID type code</param> /// <returns>the resultcode of the operation</returns> public int GetCPUType(out string CPUType, out int CPUCode) { int result = PLC.GetCpuType(out CPUType, out CPUCode); if (result != 0) { Debug.WriteLine("ERROR: " + Hex(result)); } return result; } /// <summary> /// Set the PLC CPU state. /// </summary> /// <param name="NewStatus"> /// The new state (Run/Stop/Pause)</param> public void SetCPUState(PLCStatus NewStatus) { PLC.SetCpuStatus((int)NewStatus); } /// <summary> /// Retrieves the value from a single device. /// </summary> /// <param name="device"> /// The device to retrieve the value from</param> /// <param name="deviceValue"> /// The value retrieved</param> /// <returns>the resultcode of the operation</returns> public int GetDevice(PLCDevice device, out int deviceValue) { int result = PLC.GetDevice(device.Name, out deviceValue); if (result != 0) { Debug.WriteLine("Get Device ERROR: " + Hex(result)); } //Debug.WriteLine("GET " + device.Name + " = " + deviceValue); return result; } /// <summary> /// Retrieves the value from a single device. /// </summary> /// <param name="device"> /// The device to retrieve the value from</param> /// <param name="deviceValue"> /// The value retrieved</param> /// <returns>the resultcode of the operation</returns> public int GetDevice2(PLCDevice device, out short deviceValue) { int result = PLC.GetDevice2(device.Name, out deviceValue); if (result != 0) { Debug.WriteLine("Get Device ERROR: " + Hex(result)); } //Debug.WriteLine("GET " + device.Name + " = " + deviceValue); return result; } /// <summary> /// writes a value to a single device. /// </summary> /// <param name="device"> /// The device to write the value to</param> /// <param name="deviceValue"> /// The value to write</param> /// <returns>the resultcode of the operation</returns> public int SetDevice(PLCDevice device, int deviceValue) { Debug.WriteLine("SET " + device.DeviceName + " = " + deviceValue); int result = PLC.SetDevice(device.Name, deviceValue); if (result != 0) { Debug.WriteLine("ERROR: " + Hex(result)); } return result; } /// <summary> /// writes a short value to a single device. /// </summary> /// <param name="device"> /// The device to write the value to</param> /// <param name="deviceValue"> /// The value to write</param> /// <returns>the resultcode of the operation</returns> public int SetDevice2(PLCDevice device, short deviceValue) { Debug.WriteLine("SET " + device.DeviceName + " = " + deviceValue); int result = PLC.SetDevice2(device.Name, deviceValue); if (result != 0) { Debug.WriteLine("ERROR: " + Hex(result)); } return result; } /// <summary> /// Read a contiguous block of device values. /// </summary> /// <param name="startDevice"> /// The start device of the block to read</param> /// <param name="dataSize"> /// The number of devices to read</param> /// <param name="deviceValue"> /// An array of the values returned</param> /// <returns>the resultcode of the operation</returns> public int ReadDeviceBlock(PLCDevice startDevice, int dataSize, out int[] deviceValue) { deviceValue = new int[dataSize]; int result = PLC.ReadDeviceBlock(startDevice.Name, dataSize, out deviceValue[0]); // The amount of time this output takes can cause synchronisation errors //The ideal solution would be to tell the HMI to wait until all //data reads are complete before allowing any more operations /* #if (DEBUG) Debug.Write("ReadBlock " + startDevice.DeviceName + ", " + dataSize + " = "); for (int blockIndex = 0; blockIndex < dataSize; blockIndex++) { Debug.Write(deviceValue[blockIndex] + ", "); } Debug.WriteLine(string.Empty); #endif */ return result; } /// <summary> /// Write to a contiguous block of devices. /// </summary> /// <param name="startDevice"> /// The start device of the block to write to</param> /// <param name="dataSize"> /// The number of devices</param> /// <param name="deviceValue"> /// An array of the values to write</param> /// <returns>the resultcode of the operation</returns> public int WriteDeviceBlock(PLCDevice startDevice, int dataSize, int[] deviceValue) { Debug.Write("Writeblock " + startDevice.DeviceName + ", " + dataSize + " = "); int[] blockValue = new int[dataSize]; int dataLength; if (deviceValue.Length > dataSize) { dataLength = dataSize; } else { dataLength = deviceValue.Length; } for (int blockIndex = 0; blockIndex < dataLength; blockIndex++) { blockValue[blockIndex] = deviceValue[blockIndex]; Debug.Write(blockValue[blockIndex] + ", "); } Debug.WriteLine(string.Empty); int result; if (blockValue.Length > 0) { result = PLC.WriteDeviceBlock(startDevice.Name, dataSize, ref blockValue[0]); } else { result = 0; } return result; } /// <summary> /// Retrieve a non-contiguous set of device values. /// </summary> /// <param name="devices">An array of devices to read from</param> /// <param name="deviceValue">The device values read</param> /// <returns>the resultcode of the operation</returns> public int ReadDeviceRandom(PLCDevice[] devices, out int[] deviceValue) { string deviceString = string.Empty; int dataSize = devices.Length; int result = 0; deviceValue = new int[dataSize]; if (dataSize > 0) { foreach (PLCDevice currentDevice in devices) { deviceString += currentDevice.Name + "\n"; } result = PLC.ReadDeviceRandom(deviceString, dataSize, out deviceValue[0]); } return result; } /// <summary> /// Set clock data on PLC. /// </summary> /// <param name="clockData">The date and time to which the PLC will be set</param> /// <returns>the resultcode of the operation</returns> public int SetClockData(DateTime clockData) { //NOTE FOR FX PLC's THE YEAR CAN ONLY BE 00-99 NOTE 2007 AS IN THE Q SERIES int result = PLC.SetClockData((short) ( (int) clockData.Year - 2000), (short)clockData.Month, (short)clockData.Day, (short)clockData.DayOfWeek, (short)clockData.Hour, (short)clockData.Minute, (short)clockData.Second); return result; } /// <summary> /// Write to a non-contiguous set of devices. /// </summary> /// <param name="devices">An array of devices to write to</param> /// <param name="deviceValue">The values to write</param> /// <returns>the resultcode of the operation</returns> public int WriteDeviceRandom(PLCDevice[] devices, int[] deviceValue) { string deviceString = string.Empty; int dataSize = devices.Length; foreach (PLCDevice currentDevice in devices) { deviceString += currentDevice.Name + "\n"; } Debug.Write("Writeblock " + deviceString + ", " + dataSize + " = "); for (int blockIndex = 0; blockIndex < dataSize; blockIndex++) { Debug.Write(deviceValue[blockIndex] + ", "); } Debug.WriteLine(string.Empty); int result = PLC.WriteDeviceRandom(deviceString, dataSize, ref deviceValue[0]); return result; } public bool Connected { get { return m_Connected; } set { m_Connected = value; } } } #region PLCDevice Class /// <summary> /// A class to encapsulate a PLC Device /// </summary> public class PLCDevice { DType m_DeviceType; int m_deviceID; int m_DataSize; string m_DeviceDesc; string m_DeviceName; /// <summary> /// Simple constructor, no device values set /// </summary> public PLCDevice() { } /// <summary> /// Constructor to allow multiple devices of the /// same type to be created easily. /// </summary> /// <param name="deviceType">The type of the device</param> /// <param name="deviceID">The numeric ID of the device</param> /// <param name="deviceName">The devices friendly name</param> public PLCDevice(DType deviceType, int deviceID, string deviceName) { m_DeviceType = deviceType; m_deviceID = deviceID; m_DataSize = ReturnDeviceDataSize(deviceType); m_DeviceDesc = ReturnDeviceDesc(deviceType); m_DeviceName = deviceName; } /// <summary> /// Constructor allowing devices to be created /// by providing the standard string value /// </summary> /// <param name="device">The device string</param> /// <param name="deviceName">The devices friendly name</param> public PLCDevice(string device, string deviceName) { string prefix; // Isolate the prefix letter from the device number if (device.Length < 3) { prefix = device; } else { prefix = device.Remove(2, device.Length - 2); } if (prefix.Length > 1 && (prefix[1].ToString().ToUpper() != "N")) { prefix = prefix.Remove(1, 1); } // Check the prefix is valid const string DevicePrefixes = "XYMSTCDRVZ"; int prefixIndex = -1; // If the prefix is not an empty string, search // for the prefix in the device prefixes if (prefix.Length > 0) { prefixIndex = DevicePrefixes.IndexOf(prefix.Substring(0, 1)); } // if the prefix is not found, indicate it as a // missing type, otherwise set the details to be the // correct values for the type of device if (prefixIndex == -1) { // Device type not found m_DeviceType = DType.Missing; prefix = string.Empty; } else { // Device is valid m_DeviceType = (DType)prefixIndex; m_DataSize = ReturnDeviceDataSize(m_DeviceType); m_DeviceDesc = ReturnDeviceDesc(deviceType); m_DeviceName = deviceName; } // If the device number is valid, set it if (((device.Length - prefix.Length) > 0) && (m_DeviceType != DType.Missing)) { string IDstring = device.Substring(prefix.Length, device.Length - prefix.Length); if (IsNumeric(IDstring)) { m_deviceID = Convert.ToInt32(IDstring); } else { m_deviceID = -1; } } else { m_deviceID = -1; } } /// <summary> /// Returns the desciription of the given device type /// </summary> /// <param name="deviceType">The PLC device type</param> /// <returns>The device description</returns> private string ReturnDeviceDesc(DType deviceType) { string deviceDesc = string.Empty; switch (deviceType) { case DType.X: deviceDesc = "Input"; & Edited by Nightfly

Share this post


Link to post
Share on other sites
Thank You very much Nightfly for the example. Please, inform what it was used for? In which project?

Share this post


Link to post
Share on other sites
It was for communicating to an Fx3U PLC for transferring recipes directly into the PLC and also 24/7 dataloging. We have our own PC based recipe system and data-capture program written in VB & C# that stores the data in an SQL Express database and makes pretty graphs for the end user lol. We stopped using MX component when we found out that it had problems re-connecting to PLC's when the Ethernet connection was broken. We ended going back to Mitsubishi Germany (we are UK based) to find a solution but although they knew about the problem they were not forthcoming with a solution so we started using OPC servers instead. Cost more - but built proof. MX component has been updates since (well we are on a different revision number) so this Issue may have been fixed. The code above was used on at least a dozen sites both in the USA and UK.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0