Jump to content

Search the Community

Showing results for tags 'communication'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Our Community
    • Come on in!
  • News and Announcements
    • New! UniLogic V1.21 - Supports UniStream 5"
    • VisiLogic:9.8.64 - Link to mobile app, Ladder: 2x the Space!
    • New!!! ***** U90 Ladder*****
  • UniStream HMI + PLC Programmable Controllers & UniLogic Software
    • UniStream: Hardware
    • UniLogic Software
    • UniLogic UDFBs
  • Vision, Samba, Jazz and M90 PLC + HMIs & Software
    • Vision & Samba PLC + HMI Controllers & VisiLogic Software
    • Jazz, M91 PLCs and U90Ladder
  • Software Utilities
    • SD Card Suite
    • Remote Operator
    • Remote Access
    • DataXport and DataXls
    • UniDownloader
    • UniOPC
    • UniDDE
  • Utilities for .net and Visual Studio
    • Unitronics PCOM Protocol
    • COM Object ActiveX .dll
    • .NET driver
  • Project Design
    • ...I have a project...what hardware do I need?
  • User Application Stories
    • Just finished a great project?
  • Tips and Tricks
    • Best Programming Practices
    • Tips and Tricks
  • Job Board
    • Projects seeking Programmers
    • Programmers seeking Projects
  • General Discussion
    • We're Listening...
    • The Lounge
  • News and Announcements Copy

Calendars

  • Community Calendar

Blogs

  • Unitronics' Blog: PLCs, HMIs and more
  • Saragani's Blog
  • Simon's Blog
  • Ash Neilson's Blog
  • Joe Tauser's Blog
  • Unitronics en Español
  • Powered by AMPS
  • Alldrives UK's Blog
  • Unitronics, Howman Style
  • PLCNewbie's Blog
  • Telestar Automation Blog
  • Webinars Collection
  • Tim's Corner
  • Blog
  • TELESTAR (Italian)
  • i4 Automation
  • i4 Automation (UK)
  • Unistream UDFB's

Categories

  • From Headquarters: Sample Applications
    • From Headquarters: VisiLogic
    • From Unitronics: U90 Ladder applications
  • User-submitted Applications
    • From Users: VisiLogic applications
    • From Users: U90 Applications

Categories

  • Articles
    • Forum Integration
    • Frontpage
  • Pages
  • Miscellaneous
    • Databases
    • Templates
    • Media

Categories

  • New Features
  • Other

Found 19 results

  1. Hi All! I am new to actual PLC programming and ladder logic but I have been working with Yaskawa drives for 11 years and am quite proficient on that end. I have a V1210 and have found it fairly easy to work with aside from visilogic crashing quite often on windows 10. I really want to start interfacing VFD's via modbus rs485 and I am looking for a place to start. Are their any example programs or tutorials specific to the V1000 that could help me get a start? I did see another topic similar to this, but the links the support staff listed were broken. Thanks in advance! Kyle
  2. i so far finished my ladder programming in unitronics V1040 plc and created a webpage to use in raspberry pi to view the same HMI screen in my webpage at the same time whatever output i get from the Plc HMI. now i hv the problem is, how can i communicate plc and raspberry pi.can i connect the i/o and o/p of both plc and raspberry pi . is any coding ive to write in the raspberry pi terminal for the communicate with plc. please advice me.
  3. Hello! I'm trying to configure CanOpen communication between Lenze ECSxP Posi&Shaft and Unitronics V1210. I want to set the velocity and the position using PDO1. If I give a high level to the fifteenth bit the control word becomes: First 15 bits are control bits (begin from 0) The velocity value is between 16 to 31 bits it means i can store the value using MI. The velocity is effected in the process data telegram in percent of maximum speed. And the position is between 32 to 61 bits. It is carried out in the process data telegram in resolver increments. I want to give values between 16 and 61 bits It is not possible to use MI to store the position value i need DW, however...inside CANopen Configuration block for RPDO Tx i can use only MI only ML or only DW. Could you give me suggestions how to solve the problem?
  4. Hi, I have Unitronics PLC V130-J-TR20 PLC, which is a master, and two Jazz JZ20-J-T40, which are slaves. I need two of the slave Jazz PLC's to communicate with master V130 PLC. I have made configuration in PLC Program for read and write, but it's not working properly. When i set bit for request to read PLC3 (MB100), it reads it normally. But, when i try to read PLC2, it reads same value that I have on PLC3, although Communication is OK with PLC2. I have read example project, and used it to configure communication between PLC's, like you can see in the images. Regardless of what I do, one of the PLC's is not working properly, communication says it's OK, but keeps reading values from other PLC. IP addresses are different, of course, and i have typed them correctly into the MODBUS IP Configuration, like in the image. On my Jazz PLC's I have done everything like Example project in U90 Ladder says. Is there a way of fixing this? Thankful Nikola Ljubinkovic
  5. Hi, I'm using Unitronics PLC JZ20-J-T40, and ZView SCADA. I have successfully downloaded my program into PLC, and tested communication via usb (Serial), and via Ethernet (MJ20-ET1). It's all working properly. Problem begins when i try to connect my PLC to scada PC. With USB everything is working normally, but it's not an option for me to work with usb connection. I want to work with Ethernet communication between PLC and SCADA. What should i do to make it work? Regards Nikola Ljubinkovic
  6. I am getting the following error when trying to initialize/go online for the first time with my V570. ----------------------------------------------------------------------- "Communication over TCP/IP could not be established due to one of the following reasons: - cable connections are not secure - incorrect TCP/IP settings (IP address, Protocol type, Port number) - the connection is currently being used by another application. " ----------------------------------------------------------------------- Right now the first net in my main routine is checking SB2, following by Set PLC Name, followed by a TCP/IP - Card Init, (setting IP to 192.168.1.10), and then a Socket Init (using socket 1, TCP, port 20256, and client set to server [slave]). In communication and OS I have tried my connection as both TCP/IP (Call) & TCP/IP (Listen), I am using a favorite with the same name and IP as specified above. My local machine IP is set to 192.168.1.253. I am connected directly to the ethernet port on the V570 with the V200-19-ET2 ethernet com port I am trying to "stop-download-reset" to go online and I get the above error consistently. I'm sure this is a basic question but I have watched all the tutorial videos and read the help files and I believe I am doing everything I am supposed to, any advice would be great!
  7. Hey guys, I have a UniStream 7" PLC connected with EX-RC1 expansion module via CANBUS. The CANBUS is connected according to the info in the datasheet with 120 ohm resistors and everything. The complete configuration that the PLC communicates with from left to right is as follows: EX-RC1, 3 x IO_D16A3_RO16, 2 x IO_ATC8/AI8, IO_D16_A3_RO16. The PLC and the EX-RC1 is grounded and connected as it should. EX-RC1 is programmed (initialized UniCAN) and the LEDS are all working propperly (PWR ON, I/O COMM ON, BUS COMM ON). Accordingly I am able to read/write all the inputs/outputs. So, the whole system and configuration is working propperly. A few (2-3) months later EX-RC1 dies (only PWR LED is ON). I can't read/write any of the inputs/outputs and the IO modules I mentioned earlier all blink ( no communication established). I tried restarting the whole configuration by turning the power supply OFF and then ON. Tried to reprogram the EX-RC1 but when the download starts it shows an error that the device is not available (not sure what the error said). So I thought to myself what the heck. It died, it happens and I replaced the module with a brand new one and installed a separate power supply used only for the EX-RC1. The whole configuration started working again, the comm was up and the PLC software was fully functional (able to read/write and execute). However a few months later ... surprise ... EX-RC1 dies again. The exact same circumstances. Is this a compatibility issue or? Thanks in advance for your help. Any suggestions/ideas are really appreciated.
  8. I'm trying to configure CANopen communication for a first time. NMT Status integer consists four values: 00, 7F, 05, 04. However when i press "Online test" the value is 517 (dec)?!?! - 205 (Hex). Please tell mi what it means, where is the mistake and how to fix it?
  9. Hello again, since your answers are very helpful and I could not find information I need on this forum, I`m starting new topic. I need to set up communication between V280 and multimeter DMK 22 by Lovato. Here is the tutorial they sent me: https://www.sendspace.com/file/trigbh(file is too big to be attached here on forum) I have several problems with understanding the whole communication. I have working MODBUS IP communication between PLC-to-PLC, where the communication is done through MODBUS R/W Mix, which I understand how it`s done. Here I need to get from the slave multimeter 3 values. First question: How do I send message to slave? The message should looke like this: 08 04 04 00 00 00 64 63 6A, do I have to send it as vector of HEX MIs? And the message I get back from slave will be vector too? If you don`t mind to explain this a little bit detailed including a little tutorial how to set it up correctly in VisiLogic, I`d be very happy. I have to solve this in 2 days. Thanks in advance a lot! Unitronics community is great and I will surely write it down to my thesis and recommend you. Best regards, Martin P.
  10. Hello, I'm using Jazz JZ20-R31 controller together with MJ20-RS add-on module for RS485 communication. Is there a way to use RS485 communication and simultaneously use a modem on RS232? To rephrase the question: I would like to achieve some sort of remote access to data while still communicating via RS485, are there any suitable options (modem, wifi...) ? Thank you, Best regards, Pawks
  11. Hello, if someone can help me it would be great! I just got the V-570 PLC and had it wired up to my inputs and outputs, and wanted to test it out. I have two issues I need to fix: First I tried to upload my project to the SD card, and put it in the PLC and run it. I wanted to see if I could just do basic screen navigation first. However, when I ran the program, after clicking on the first screen, it glitched out and turned a solid blue with no buttons. I figured it was a coding error on my part, but how do I take the program off of the PLC and restore it to the little animation sequence it had when I first turned it on? When I turn the maching off and on again it just goes back to the solid blue screen I had before. The second issue is, i figure to stop this from happening again I can debug it by the online test mode. However, when I followed the instructions to install the drivers and plugged the USB in, it said the port was not open and "may be used by another application". Is this a network firewall issue? I've attached the screen that comes up. If someone can help that would be great, I'm new to all of this and worried I might break something if I try to fix this myself. Thanks in advance!
  12. Hello, I have a .net application that connects to a 570 via RS-232 using System.IO.Ports.SerialPort. Normally, it will connect. However, when playing with different baud rates, it sometimes does not connect until I connect the same PC with any Unitronics software (Visilogic or Remote Operator). My question is this: With VIsilogic, it appears that you can define the baud rate to anything in the connection properties and it always connects. How does the controller adapt accordingly? I think "out of the box", the rate is set to 115200. If I change my application to 57600, it failes to connect. But, if I connect using Visilogic @ 57600 it works. I go back to my application and then it works. I am trying to determine what Visilogic is doing that I am not. My connection looks like this: // Connect to the PLC try { string comPort = Properties.Settings.Default.CommPort; int comBdRate = Properties.Settings.Default.CommBdRate; int comTimeOut = Properties.Settings.Default.CommTimeOut; _serialPort.PortName = comPort; _serialPort.BaudRate = comBdRate; _serialPort.DataBits = 8; _serialPort.Parity = Parity.None; _serialPort.Handshake = Handshake.None; _serialPort.ReadTimeout = comTimeOut; _serialPort.NewLine = "\r"; _serialPort.Open(); } catch (Exception) { // Disconnect from the PLC _serialPort.Close(); } Once this executes, I begin sending PCOM commands: try { // Send the message out the serial port. _serialPort.DiscardInBuffer(); _serialPort.WriteLine(message); // Verify the message was received, catch the timeout string response = _serialPort.ReadTo("/A00SBF5"); if (response == "/A00SBF5") { //do nothing, success!! } } catch (Exception) { _connectionLost = true; _serialPort.Close(); return -1; } The _serialPort.ReadTo() catches the timeout (default 1 sec). When that occurs, we assume we lost the connection. Is there something I should be doing to prime the port first? Thanks!
  13. Hello, We have a problem with Unitronics Jazz 2 series PLCs (JZ20-R31, +adapters MJ20-RS) trying to connect to modbus communication line. The problem is we cant initializate RS-485 com port, every configuration are restored to factory default (9600;7;1;even;n) after RS-485 cable connection to PLC and in system menu it is impossible to change communication parameters if RS-485 cable is connected (RS-232 com port we do not use). We do not have any problems with Jazz 1 series plcs using almost same program, same configuration. + U90 ladder we are using last version (v6.4.9) + Unitronics 2 series OS is last version (V2.30 (B08)) + Communication line is good (we checked). + We have two Jazz 2 series plcs with same problem. P.S sorry for my english.
  14. Hello, Is there a way to read/write (send) data between 2 plc's via gprs modem, using pcom? I'm using V130 and Siemens TC65 at both ends Thanks in advance!
  15. hi, I have a project and require communication between a ABB drive and V280 unitronics, where v280 is the master, anyone can help me or suggest how I start? thanks, pd. I have done this type of communication but with other brands, this brand only cut I made the flight program without communication inputs and outputs only analog and digital.
  16. Hi, Can i MJ10-22-CS25 cable (programming cable) for modbus communication between my PC to M91-2-T38? thanks, Nikita1
  17. Hello! I can no longer download to the V570 via ethernet only via COM1. With 9.4.0, at the beginning happened once in a while and now I can no longer download the program in any way for LAN, I have to connect the serial network. I get notifications that communication fell after "Build info DLUs tables." The remote operator, online test from visilogic, webserver, Modbus, and other communication protocols are normal. I already sent the data to support and am waiting for support. Somebody had something similar, or any thoughts?
  18. Build your own SD Card Explorer

    People who see the SD Card Explorer in action usually sometimes wish to have the same functionality in their own application.Some of them contact Unitronics in order to get some details on the protocol, or ways that they can do the same, while others fear from the worst: that it's a lot of work.I know very few people that will be happy to write the whole protocol by themselves.The only guy I can think of in that matter is Ash Nielson... I have no idea where he gets his strength and energy from, but the solution for this problem is actually simpler than you think.You don't have to be energetic as Ash in order to write your own SD Card Explorer because the .Net communication driver actually contains all the logic If you don't know what the .Net communication driver, then please refer to the Downloads section on the main website (not the forum) it has some examples + the source code of the .Net communication driver.For those of you who does know how to work with it, I can assume that you are already familiar with the all mighty and magical PLC object.Within the PLC object, hides a small sub class called SD.This class gives all the capabilities of reading and writing files and also listing directories and deleting files.So how do we get started:Lets assume that we have a Serial port called serialLets create a PLC object:PLC plc = PLCFactory.GetPLC(serial, 0);All the code that I will write will be in C#, but the syntax in VB.net is not much different.Now that we have a PLC object called plc, we can access it's SD Class.Please note that SD capabilities are only available to the Enhanced PLCs (V570/V130/V350).Before I give any more code examples, I'll list the Public functions inside the SD Class:public Folder Dir(ProgressStatusChangedDelegate del)Returns a Dir of all Folders and files in the SD (Dirs the Root). ProgressStatusChanged is being used to return the Status, Pecentage and Action of the current Statuspublic Folder Dir(SdFolder sdFolder, string filesExtension, bool scanSubFolders, ProgressStatusChangedDelegate del)Requests Dir Syncrhronously. Accepts SdFolder enum as the path to list, extension for example "*.*", and some other paremeterspublic Folder Dir(string folderName, string filesExtension, bool scanSubFolders, ProgressStatusChangedDelegate del)Requests Dir Syncrhronously. Same as above, but path is string and not enumpublic byte[] ReadFile(string folderName, string fileName, ProgressStatusChangedDelegate del)Read File Syncrhronously. Reads the whole file from SD and then returns it's content as Byte Arraypublic byte[] ReadFile(SdFolder sdFolder, string fileName, ProgressStatusChangedDelegate del)Read File Syncrhronously. Reads the whole file from SD and then returns it's content as Byte Array.Gets SdFolder as path instead of stringpublic void ReadFile(string sourceFolderName, string sourceFileName, string targetFolder, bool resumeRead, ProgressStatusChangedDelegate del)Read File Syncrhronously. Reads the file and each chunk that is being read is instantly written into diskpublic void WriteFile(SdFolder sdFolder, string fileName, byte[] fileContent, ProgressStatusChangedDelegate del)Write File Syncrhronously. Since we only allow writing files into Authorized folders only then this function only accepts SdFolder enum as path and not as stringpublic void DeleteFile(string folderName, string fileName, ProgressStatusChangedDelegate del)Deletes a file... DUHH!!! (Sorry, I had to do that)public void DeleteFile(SdFolder sdFolder, string fileName, ProgressStatusChangedDelegate del)Same as above, but with SdFolder enum as pathAlso consider using:public static string GetSdFolderAsString(SdFolder sdFolder)and the opposite function:public static SdFolder GetSdFolderFromString(string path)Coming up next... Real code. SD Card Explorer Code revealed.Come back to our next episode next week
  19. You are probably saying to yourself "Hey, you promised that the next episode of 'Build your own SD Card Explorer' will be published, so how come Saragani posts about something else?"Well, I actually said that the next episode will be posted next week :-)It is going to have a lot of code and it will be a lot of work writing it so I might split it to few pieces.Besides, I can use this blog entry to post about new features of the Com Driver.I wrote this multi listener a while ago, but the source code of the communication driver was not published since then.You might assume that writing the Multi-Listener was harder than writing the single listener, but it is actually the opposite..Net gives you an easy way to write a multi-listener and for having a single listener I had to manipulate the system to have just 1 connection (Lets say that in order to stop listening, I had to close the port, but then it caused the socket to be disposed so I had to create a new instance... and events from other threads and some other stuff sometimes caused Threads races).We didn't write the Multi Listener on the first place since we actually needed a single socket listener for the apps that use the communication driver, and we didn't extend the single listener to to multi listener because it will break the compatibility.Lets start:There are 2 new channels: ListenerServer and ListenerClient (Where ListenerClient have an internal constructor, cause it can only be created by the ListenerServer).ListenerServer is just like the EthernetListener, but it allows multiple connections (It means that several PLCs can connect to the PC on the same time and to the same port).Unlike the EthernetListener, the ListenerServer does not contain any logic for sending and receiving data. When communication is being accepted, the ListenerServer creates a new ListenerClient. If it manages to create a PLC object then it will be returned to the user by an event. The Plc will contain the ListenerClient.Few notes:1) The ListenerServer contains only 2 types of statuses: Listening and Disconnected (“Connected” is irrelevant since it is a property of the Client…)2) When a PLC object that uses a ListenerClient channel have the connection closed, the PLC object can’t be used anymore (It is being disposed).3) In the EthernetListener (The old Single connection Listener) calling PLC.Disconnect or ethernetListener.Disconnect closes the client connection. With the new ListenerServer PLC.Disconnect closes the connection of the specific PLC (Closes a specific client), and ListenerServer.Disconnect closes the Listen (The status changes from Listening to Disconnected).4) Just like before, if the Message Queue is not empty then Plc.Disconnect doesn’t close the connection. When using ListenerServer/ListenerClient, you can call PLC.Dispose which closes the connection no matter how many messages are in the queue.a. It is a good practice to Dispose a PLC if the ListenerClient is no longer needed/In use (To close unused sockets). b. When the PLC object has no references then it will be collected by the GC and therefore the ListenerClient will also be collected by the GC. The destructor of the ListenerClient currently does not contain any “Socket.Close” (This might change in the future). I believe that the socket will be closed when the channel will be collected by the GC, but you can never tell when the GC will decide to run.c. Dispose a PLC only when it’s ListenerClient is no longer needed. For example: PLC plc; PLC plc2; private void Listen() { try { PLCFactory.GetChannel(LOCAL_PORT, out listenerServer); if (listenerServer == null) listenerServer = new ListenerServer(LOCAL_PORT, 3, 3000); listenerServer.OnConnectionAccepted += new ListenerServer.ConnectionAcceptedDelegate(listenerServer_OnConnectionAccepted); listenerServer.OnConnectionStatusChanged += new ListenerServer.ConnectionStatusChangedDelegate(listenerServer_OnConnectionStatusChanged); PLCFactory.GetPLC(listenerServer); listening = true; } catch (Exception ex) { MessageBox.Show(ex.Message); } } void listenerServer_OnConnectionAccepted(PLC plcFromListener) { plc = plcFromListener; plc2 = PLCFactory.GetPLC((plcFromListener.PLCChannel as ListenerClient),2); // Get the PLC on Unit ID 2 (Assuming that plcFromListener is Unit ID 1. plcFromListener.Dispose(); // This will also cause plc2 to disconnect cause plc2 is using the same resource (The same ListenerClient) } However, if plc was created from one from of the OnConnectionAccepted event calls and plc2 was created from a different call of OnConnectionAccepted then those 2 PLC object will have different ListenerClient object, so disposing 1 PLC does not affect the other one.As I'm a fan of WPF and Binding, then I will write the example in WPF. It doesn't affect how you use the Com Driver, but it makes my life easier when the UI doesn't have any Business Logic.If I also change properties from another thread, then the UI will not crash since OnPropertyChanged protects me (it uses the Dispatcher in order to use the UI thread).If you are using WinForms then you will have to use this.BeginInvoke on the form etc...Lets start an MVVM solution.Since we support several clients then we will need a class that represents a single client (And we will have a list of all the clients in order to keep tracking on them and disconnect them if needed).I'll call this class ClientViewModel and it will inherit the ViewModelBase. public class ClientViewModel : ViewModelBase { } The Client will need to contain the PLC Object, we will want to show the IP of the client, the PLC Model, the OS Version and a value of an Operand (Lets take SDW 0 since it has an Auto Increment).I'll make it simple, I will have all those properties (Except the PLC object) as Strings).I also need a Timer that will Tick every once in a while and request the Value of SDW 0. public class ClientViewModel : ViewModelBase { private PLC plc; private string clientIP; private string plcModel; private string osVersion; private string plcName; private string sdw0; Timer timer; } What I also need is a way to Disconnect, Run, Stop, Restart etc the PLC so I will use a DelegateCommand which is a class in the MVVM template that inherits from the ICommand Interface.I also need a way to tell the main class (MainViewModel) that the Client has disconnected, so I will use an Even in this case: public class ClientViewModel : ViewModelBase { private PLC plc; private string clientIP; private string plcModel; private string osVersion; private string plcName; private string sdw0; Timer timer; private DelegateCommand disconnectClientCommand; private DelegateCommand resetPlcCommand; private DelegateCommand stopPlcCommand; private DelegateCommand runPlcCommand; public event EventHandler OnConnectionClosed; Now lets start adding the code to this class: public class ClientViewModel : ViewModelBase { private PLC plc; private string clientIP; private string plcModel; private string osVersion; private string plcName; private string sdw0; Timer timer; private DelegateCommand disconnectClientCommand; private DelegateCommand resetPlcCommand; private DelegateCommand stopPlcCommand; private DelegateCommand runPlcCommand; public event EventHandler OnConnectionClosed; public ClientViewModel(PLC plcFromListener) { plc = plcFromListener; (plc.PLCChannel as ListenerClient).OnConnectionClosed += new ListenerClient.ConnectionClosedDelegate(ClientViewModel_OnConnectionClosed); ClientIP = (plc.PLCChannel as ListenerClient).RemoteIP; PlcVersion version = plc.Version; PlcModel = version.OPLCModel; OsVersion = version.OSVersion + "(" + version.OSBuildNum + ")"; Action action = delegate() { PlcName = plc.PlcName; }; action.BeginInvoke(null, null); timer = new Timer(100); timer.Elapsed += new ElapsedEventHandler(timer_Elapsed); timer.Start(); } void ClientViewModel_OnConnectionClosed(ListenerClient ethernetListener) { if (timer != null) timer.Stop(); if (OnConnectionClosed != null) OnConnectionClosed(this, null); } public string ClientIP { get { return clientIP; } internal set { clientIP = value; OnPropertyChanged("ClientIP"); } } public string PlcModel { get { return plcModel; } internal set { plcModel = value; OnPropertyChanged("PlcModel"); } } public string OsVersion { get { return osVersion; } internal set { osVersion = value; OnPropertyChanged("OsVersion"); } } public string PlcName { get { return plcName; } internal set { plcName = value; OnPropertyChanged("PlcName"); } } public string Sdw0 { get { return sdw0; } internal set { sdw0 = value; OnPropertyChanged("Sdw0"); } } public ICommand DisconnectClientCommand { get { if (disconnectClientCommand == null) { disconnectClientCommand = new DelegateCommand(disconnectClient); } return disconnectClientCommand; } } private void disconnectClient() { try { // When using a Listener Server, it is important to close the connection to the PLC // if it's not needed anymore. plc.Disconnect closes the connection only if there are no // pending messages in the queue (This is why it is important to abort the communication before disconnecting). // However, plc.Dispose will allow you to close the connection anyway (if other PLC objects use the same connection // which is the same ListenerClient) then they will become diposed as well. // Dispose method is only relevant to ListenerClient connections. plc.Dispose(); } catch { } } public ICommand ResetPlcCommand { get { if (resetPlcCommand == null) { resetPlcCommand = new DelegateCommand(resetPlc); } return resetPlcCommand; } } private void resetPlc() { try { // Reseting the PLC will cause the connection to be closed. // If the PLC is connected directly to the PC using a cable then the PC should get a disconnection event. // However, if there is a hub in the middle the PC will get the disconnection event only after it tries to communicate with the PLC. // In this example we read SDW 0 every 100ms which will cause the connection to be "tested" just like mentioned above. plc.Reset(); } catch { } } public ICommand StopPlcCommand { get { if (stopPlcCommand == null) { stopPlcCommand = new DelegateCommand(stopPlc); } return stopPlcCommand; } } private void stopPlc() { try { plc.Stop(); } catch { } } public ICommand RunPlcCommand { get { if (runPlcCommand == null) { runPlcCommand = new DelegateCommand(runPlc); } return runPlcCommand; } } private void runPlc() { try { plc.Run(); } catch { } } void timer_Elapsed(object sender, ElapsedEventArgs e) { try { ReadWriteRequest[] rw = new ReadWriteRequest[1]; rw[0] = new ReadOperands() { NumberOfOperands = 1, OperandType = OperandTypes.SDW, StartAddress = 0, }; plc.ReadWrite(ref rw); Sdw0 = ((rw[0].ResponseValues as object[])[0]).ToString(); } catch (ComDriveExceptions cde) { if (cde.ErrorCode == ComDriveExceptions.ComDriveException.ObjectDisposed) { plc.Dispose(); } } catch (Exception ex) { } } } We are done with the ClientViewModel... Now we can start with the MainViewModel.We want a list of ClientViewModels, so we will use an ObservableCollection that can be easily binded to a ListBox or any ItemsContainer: public class MainViewModel : ViewModelBase { private ObservableCollection<ClientViewModel> clients = new ObservableCollection<ClientViewModel>(); } We need an option of the UI to tell the MainViewModel to Start or Stop Listening. We will again use a DelegateCommand. public class MainViewModel : ViewModelBase { private ObservableCollection<ClientViewModel> clients = new ObservableCollection<ClientViewModel>(); private DelegateCommand exitCommand; private DelegateCommand listenCommand; private DelegateCommand disconnectCommand; } We also want a boolean that will tell the UI if we are Listening or not, we need a reference to the ListenerServer (The Server Channel that we have created) in order to tell it to Start Listening or Stop Listening.I'm going to have the port that we listen to as a Const:private const int LOCAL_PORT = 20275;I also need a Status (Ready, Listening, etc). Lets make it a String.And just one last thing:Observable Connection isn't thread safe, so if the collection is binded to the UI and we alter it from a different thread then we will get an Excetion.Therefore, we need a Dispatcher.The code is: public class MainViewModel : ViewModelBase { private ObservableCollection<ClientViewModel> clients = new ObservableCollection<ClientViewModel>(); private DelegateCommand exitCommand; private DelegateCommand listenCommand; private DelegateCommand disconnectCommand; private bool listening = false; private ListenerServer listenerServer; private const int LOCAL_PORT = 20275; private string status; private Dispatcher dispatcher; #region Constructor public MainViewModel() { Status = "Ready"; dispatcher = Dispatcher.CurrentDispatcher; } #endregion } Lets start addting some properties (Public properties with OnPropertyChanged: public ObservableCollection<ClientViewModel> Clients { get { return clients; } internal set { clients = value; OnPropertyChanged("Clients"); } } public string Status { get { return status; } internal set { status = value; OnPropertyChanged("Status"); } } We also need to add the ICommand properties we make the program Exit, Listen or Disconnect (Close the Listener). public ICommand ExitCommand { get { if (exitCommand == null) { exitCommand = new DelegateCommand(Exit); } return exitCommand; } } private void Exit() { Application.Current.Shutdown(); } public ICommand ListenCommand { get { if (listenCommand == null) { listenCommand = new DelegateCommand(Listen, canListen); } return listenCommand; } } private bool canListen() { return !listening; } private void Listen() { try { PLCFactory.GetChannel(LOCAL_PORT, out listenerServer); if (listenerServer == null) listenerServer = new ListenerServer(LOCAL_PORT, 3, 3000); listenerServer.OnConnectionAccepted += new ListenerServer.ConnectionAcceptedDelegate(listenerServer_OnConnectionAccepted); listenerServer.OnConnectionStatusChanged += new ListenerServer.ConnectionStatusChangedDelegate(listenerServer_OnConnectionStatusChanged); PLCFactory.GetPLC(listenerServer); listening = true; } catch (Exception ex) { MessageBox.Show(ex.Message); } } void listenerServer_OnConnectionStatusChanged(EthernetListener.ConnectionStatus connectionStatus) { // You can also use a timer to scan the status every, lets say, 1 second. updateStatus(connectionStatus); } private void updateStatus(EthernetListener.ConnectionStatus connectionStatus) { string text = ""; switch (connectionStatus) { case EthernetListener.ConnectionStatus.Listening: text = "Listening, Connected Clients: " + getNumberOfClients().ToString(); break; case EthernetListener.ConnectionStatus.Disconnected: text = "Disconnected, Connected Clients: " + getNumberOfClients().ToString(); break; } Status = text; } void listenerServer_OnConnectionAccepted(PLC plcFromListener) { // This event is not raised from the GUIs thread. Therefore we need to invoke it on the // Main thread using the dispatcher. It is important to create the viewmodels in the GUI threa // cause we want the dispatcher of the viewmodels to be associated with the right thread. Action action = delegate() { ClientViewModel clientViewModel = new ClientViewModel(plcFromListener); clientViewModel.OnConnectionClosed += new EventHandler(clientViewModel_OnConnectionClosed); clients.Add(clientViewModel); updateStatus(listenerServer.Status); refreshIndexes(); }; dispatcher.Invoke(action, null); } void clientViewModel_OnConnectionClosed(object sender, EventArgs e) { try { Action action = delegate() { clients.Remove(sender as ClientViewModel); updateStatus(listenerServer.Status); refreshIndexes(); }; dispatcher.Invoke(action, null); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void refreshIndexes() { ICollectionView view = CollectionViewSource.GetDefaultView(Clients) as ListCollectionView; view.Refresh(); } public ICommand DisconnectCommand { get { if (disconnectCommand == null) { disconnectCommand = new DelegateCommand(Disconnect, canDisconnect); } return disconnectCommand; } } private bool canDisconnect() { return listening; } private void Disconnect() { if (listenerServer != null) { try { listenerServer.Disconnect(); listenerServer.OnConnectionAccepted -= new ListenerServer.ConnectionAcceptedDelegate(listenerServer_OnConnectionAccepted); listening = false; } catch (Exception ex) { MessageBox.Show(ex.Message); } } } private int getNumberOfClients() { int result = 0; Details detail = ListenerClientsInfo.GetDetails(LOCAL_PORT); if (detail != null) { result = detail.Count; } return result; } This ends the MainViewModel code... The compelte MainViewModel Code is: public class MainViewModel : ViewModelBase { private ObservableCollection<ClientViewModel> clients = new ObservableCollection<ClientViewModel>(); private DelegateCommand exitCommand; private DelegateCommand listenCommand; private DelegateCommand disconnectCommand; private bool listening = false; private ListenerServer listenerServer; private const int LOCAL_PORT = 20275; private string status; private Dispatcher dispatcher; #region Constructor public MainViewModel() { Status = "Ready"; dispatcher = Dispatcher.CurrentDispatcher; } #endregion public ObservableCollection<ClientViewModel> Clients { get { return clients; } internal set { clients = value; OnPropertyChanged("Clients"); } } public string Status { get { return status; } internal set { status = value; OnPropertyChanged("Status"); } } public ICommand ExitCommand { get { if (exitCommand == null) { exitCommand = new DelegateCommand(Exit); } return exitCommand; } } private void Exit() { Application.Current.Shutdown(); } public ICommand ListenCommand { get { if (listenCommand == null) { listenCommand = new DelegateCommand(Listen, canListen); } return listenCommand; } } private bool canListen() { return !listening; } private void Listen() { try { PLCFactory.GetChannel(LOCAL_PORT, out listenerServer); if (listenerServer == null) listenerServer = new ListenerServer(LOCAL_PORT, 3, 3000); listenerServer.OnConnectionAccepted += new ListenerServer.ConnectionAcceptedDelegate(listenerServer_OnConnectionAccepted); listenerServer.OnConnectionStatusChanged += new ListenerServer.ConnectionStatusChangedDelegate(listenerServer_OnConnectionStatusChanged); PLCFactory.GetPLC(listenerServer); listening = true; } catch (Exception ex) { MessageBox.Show(ex.Message); } } void listenerServer_OnConnectionStatusChanged(EthernetListener.ConnectionStatus connectionStatus) { // You can also use a timer to scan the status every, lets say, 1 second. updateStatus(connectionStatus); } private void updateStatus(EthernetListener.ConnectionStatus connectionStatus) { string text = ""; switch (connectionStatus) { case EthernetListener.ConnectionStatus.Listening: text = "Listening, Connected Clients: " + getNumberOfClients().ToString(); break; case EthernetListener.ConnectionStatus.Disconnected: text = "Disconnected, Connected Clients: " + getNumberOfClients().ToString(); break; } Status = text; } void listenerServer_OnConnectionAccepted(PLC plcFromListener) { // This event is not raised from the GUIs thread. Therefore we need to invoke it on the // Main thread using the dispatcher. It is important to create the viewmodels in the GUI threa // cause we want the dispatcher of the viewmodels to be associated with the right thread. Action action = delegate() { ClientViewModel clientViewModel = new ClientViewModel(plcFromListener); clientViewModel.OnConnectionClosed += new EventHandler(clientViewModel_OnConnectionClosed); clients.Add(clientViewModel); updateStatus(listenerServer.Status); refreshIndexes(); }; dispatcher.Invoke(action, null); } void clientViewModel_OnConnectionClosed(object sender, EventArgs e) { try { Action action = delegate() { clients.Remove(sender as ClientViewModel); updateStatus(listenerServer.Status); refreshIndexes(); }; dispatcher.Invoke(action, null); } catch (Exception ex) { MessageBox.Show(ex.Message); } } private void refreshIndexes() { ICollectionView view = CollectionViewSource.GetDefaultView(Clients) as ListCollectionView; view.Refresh(); } public ICommand DisconnectCommand { get { if (disconnectCommand == null) { disconnectCommand = new DelegateCommand(Disconnect, canDisconnect); } return disconnectCommand; } } private bool canDisconnect() { return listening; } private void Disconnect() { if (listenerServer != null) { try { listenerServer.Disconnect(); listenerServer.OnConnectionAccepted -= new ListenerServer.ConnectionAcceptedDelegate(listenerServer_OnConnectionAccepted); listening = false; } catch (Exception ex) { MessageBox.Show(ex.Message); } } } private int getNumberOfClients() { int result = 0; Details detail = ListenerClientsInfo.GetDetails(LOCAL_PORT); if (detail != null) { result = detail.Count; } return result; } } Now it is time to design the UI :-)The MainView which is a Window that comes with the MVVM Template and it contains Key Binding to the Exit Command (So we can do a Ctr+X).Beside that we also need a Converter so the items in the Listbox will have an Index. class PositionConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { ListBoxItem item = value as ListBoxItem; ListBox view = ItemsControl.ItemsControlFromItemContainer(item) as ListBox; int index = view.ItemContainerGenerator.IndexFromContainer(item); return index.ToString(); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new Exception("The method or operation is not implemented."); } } The UI Xaml Is: <Window x:Class="Listener_Server_Example.Views.MainView" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:c="clr-namespace:Listener_Server_Example.Commands" xmlns:local="clr-namespace:Listener_Server_Example" Title="Main Window" Height="400" Width="800" WindowState="Maximized"> <Window.Resources> <!-- Allows a KeyBinding to be associated with a command defined in the View Model --> <c:CommandReference x:Key="ExitCommandReference" Command="{Binding ExitCommand}" /> <local:PositionConverter x:Key="positionConverter"/> </Window.Resources> <Window.InputBindings> <KeyBinding Key="X" Modifiers="Control" Command="{StaticResource ExitCommandReference}" /> </Window.InputBindings> <DockPanel> <Menu DockPanel.Dock="Top"> <MenuItem Header="_File"> <MenuItem Command="{Binding ExitCommand}" Header="E_xit" InputGestureText="Ctrl-X" /> </MenuItem> </Menu> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <ListView SelectionMode="Single" Grid.Row="0" ItemsSource="{Binding Clients}" x:Name="listView1"> <ListView.View> <GridView AllowsColumnReorder="False"> <GridViewColumn Header="Index" DisplayMemberBinding="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBoxItem}, Converter={StaticResource positionConverter}}" Width="50" /> <GridViewColumn Header="Client IP" DisplayMemberBinding="{Binding ClientIP}" Width="Auto"/> <GridViewColumn Header="PLC Model" DisplayMemberBinding="{Binding PlcModel}" Width="Auto"/> <GridViewColumn Header="OS Version" DisplayMemberBinding="{Binding OsVersion}" Width="Auto"/> <GridViewColumn Header="PLC Name" DisplayMemberBinding="{Binding PlcName}" Width="Auto"/> <GridViewColumn Header="SDW 0" DisplayMemberBinding="{Binding Sdw0}" Width="Auto"/> <GridViewColumn Header="Actions" Width="Auto"> <GridViewColumn.CellTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Button Content="Disconnect Client" ToolTip="Closes the connection to the PLC" Command="{Binding DisconnectClientCommand}" Margin="2" /> <Button Content="Reset PLC" ToolTip="Reset PLC" Command="{Binding ResetPlcCommand}" Margin="2"/> <Button Content="Stop PLC" ToolTip="Stop PLC" Command="{Binding StopPlcCommand}" Margin="2" /> <Button Content="Run PLC" ToolTip="Run PLC" Command="{Binding RunPlcCommand}" Margin="2"/> </StackPanel> </DataTemplate> </GridViewColumn.CellTemplate> </GridViewColumn> </GridView> </ListView.View> </ListView> <StackPanel Orientation="Horizontal" Grid.Row="1"> <Button Content="Listen" Margin="2" ToolTip="Start Listening to port 20275" Command="{Binding ListenCommand}"/> <Button Content="Disconnect" Margin="2" ToolTip="Stop Listening to port 20275. Connected clients will still be connected." Command="{Binding DisconnectCommand}"/> </StackPanel> <StatusBar Grid.Row="2"> <StackPanel Orientation="Horizontal"> <TextBlock Text="Status: " Margin="2"/> <TextBlock Text="{Binding Status}" Margin="2"/> </StackPanel> </StatusBar> </Grid> </DockPanel></Window> We have a ListView with several columns and a DataTemplate With Disconnect, Reset, etc buttons.I've attached the complete solution.If you find bugs or have suggestions to improve stuff then please don’t hesitate to contact me.Thank you.
×