Jump to content

Search the Community

Showing results for tags 'PLC'.



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.24 introduces VFDS from Unitronics!!
    • 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
    • Industry 4.0, IioT, MQTT--Looking forward
  • 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

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

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


AIM


MSN


Website URL


ICQ


Yahoo


Jabber


Skype


Location


Interests

Found 68 results

  1. Anyone know if the Unistream platform would be capable of handling up to 32 analog inputs and 36+ digital outputs? This would be controlled via RS485 through a banner serial radio (link below). The master radio (wired to the unistream) would have 4 or 5 slave radios wired rs485 to 4 or 5 remote i/o devices (red lion i/o link below). http://www.bannerengineering.com/en-US/wireless/surecross_web_multihop http://www.redlion.net/product/ethertrak-2-io-module-32-mixed-inputsoutputs I'm not looking for super fast speeds but it needs to be dependable. There will be no analog outputs or highspeed counters if that makes a difference.
  2. Hello, I'm currently trying to make a PLC program and HMI interface with UniLogic. The problems I've faced so far: Is it possible to set a default colour for buttons and backgrounds? Say for example you make a new screen, it's set to light blue, when I'd like it to be a different colour. And the default colour for buttons is darker blue when it'd be great to be able to set the default colour yourself. Or if you could set your own colour palette (for example replace the dark blue with dark green, and light blue with light green). The "border thickness" of buttons doesn't work with black (FF000000). No matter how thick I set the border, it just makes the button smaller. Making "border" a taboo search word on the forum doesn't help eighter. If I make the colour FF000001 instead of FF000000, it works. So having FF000000 as the default colour isn't really that effective. I also find it very irritating how when I set a colour, if I move the mouse outside of the colour selection window it reverts back to what it was. I have moved the mouse outside of the window several times accidentally and it can be quite frustrating. When I started out with an empty screen, I tried to place a button. I accidentally tried to set the "start position" of the button outside the border of the screen, so when I released the mouse button, UniLogic crashed. Some positive things to even it out: I really like the little preview window when you hold your cursor over a screen <3 Thanks, Exouxas
  3. Hello! I have to connect PLC and PC which are placed in different towns. I need to read data from PLC and to download/write data to PLC. If anybody has an experience with this issue, please share. Regards!
  4. Hello! Another one topic about PLC/E-mail, unfortunately, I'm not able to copy with the problem... I use the ladder from Example (of course). I setted up PLC's IP, mask and gateway. Firstly, I wrote "telnet pop.gmail.com 25" in CMD to see the protocol type used by the e-mail server - ESMTP. After that I dial the text "ping pop.gmail.com" to see the IP address of the server. I changed a setting in "TCP/IP-Tcp Connect" block. The "Remote IP" inside the block is equal to IP address of the server. The last change is in "E-Mail" block. "From:" e-mail is "support@unitronics.com" and "To:" e-mail is "..........@gmail.com". When i press "Connect" in HMI the connection is done. However when I press "Send E-mail" the program shows two different errors: "'From' address format incorrect"; "The server cannot receive data (DATA mode error)". Please, tell me where might be the mistakes to try to solve them!
  5. Hello all! i m new to unitronics and PLC programming. I have troubles finding solved examples for PLC programming. Right now i have a task to finish and i m really struggling to understand ladder programming for PLC. I would be glad and thankfull if there is anyonne to help me about helping solving my task. Reply me here if u interested so i can show u how what is my task. Thanks
  6. Hello, I am designing a rig for a very fast, time sensitive experiment. The end result is to have a plot with pressure change versus time, so it needs to measure on the order of miliiseconds. I have a Vision 570, and the newest software. I already am able to take ~10 ms increment data and store it into a data table. Is there any way to record the RTC in milliseconds and store that in the data table as well? The system Integers don't seem to have that precision. Note: I do NOT want the scan time resolution, I want the actual time the data point is being taken, so I will need either a timer or real time clock that has this precision. Thanks in advance!!
  7. Samba™ is an all-in-one palm-sized HMI + PLC + onboard I/Os. As a trendsetter in the field of all-in-one PLC + HMI integrated controllers, Unitronics has specifically developed Samba for applications that require PLC control, but that are limited by budget to simple text displays. System integrators and OEMs often develop applications that require PLC control, but that settle on simple text displays due to limited budget. Samba's beautiful HMI 3.5” QVGA 16-bit touchscreen enables data entry and display of variable data, including color Trend graphs and alarm screens. The HMI supports 24 user-designed screens, and up to 40 images per application. The integrated PLC controller offers a broad range of features including 2 auto-tuned PID loops, time-based RTC control, datalogging, recipes and more. Internal memory holds 0.5 MB of application logic, plus 512K for fonts and 0.5 MB for images. Onboard I/Os offer digital, analog, and high-speed functionality. The flat fascia and IP66/IP65/NEMA4X rating makes Samba an excellent fit for the food & pharmaceutical industries--ideal wherever spray/wipe down requirements apply. Samba offers a built-in RS232 port. You can add an additional RS485 serial, Ethernet, or CANbus port. Samba supports GPRS/GSM, email, SMS, as well as industrial TCP/IP protocols, MODBUS, DF1 slave, CANopen, J1939 and more—and it may be adapted to any 3rd-party protocol. Unitronics free VisiLogic software provides a single simple environment for hardware and communications configuration, Ladder application development, and HMI design, including a free library of industrial images. Free utilities support remote PC access and data export. Unitronics offers free technical support for all of their products, and an active user forum. Samba offers all the functionality system integrators need for small applications, reduces space requirements, wiring, and eliminates the need to set up Panel-PLC communication—resulting in an excellent price/performance ratio. For more information, go to: http://www.unitronics.com/plc-hmi/samba
  8. I purchased a UAC-02RS2 so I could connect a radio and need to configure the com port for Modbus slave. Is there an example? Radio does not use RS285 or Ethernet and I would prefer not having to purchase a converter to convert to RS485 thus the additional com ports.
  9. Example applications--Communications, HMI, UDFBs, Email...etc.etc.etc. may be downloaded from here: http://www.unitronics.com/Downloads/Support/UniLogic/UniLogic%20Example%20Projects.zip
  10. Good afternoon, Is it possble to upload a PLC program from a connected PC programmicly? I've using the Vision 230 in a peice of equipment with 100+ installations around the world, recently we added several features that we need to distrubute to all the PLC's From a hardware standpoint, we have a supervisory computer connected to #1 RS232 port. We distrubute the PC Superviory software via windows click-once, I'd like to build a batch file that would run post appilcation installation to update the PLC. 1) has anyone every done a project that the PLC code is distrubuted with a Visual Studio based Application? 2) any example code available illistrating this process? Thanks in advance. Aaron
  11. Hello all, For my final theoretical project for my college course, I am required to build something which requires a PLC or a microcontroller. I have decided to build a portable PLC controlled rotiserrie machine. I haven't determined all the parts that I need for this project yet, but was wondering if someone can help me out figure out if its possible I belive that the Unitronics M91 PLC wll be suitable for this project. I will have a portable 12VDC supply (Car Booster Pack) to power the PLC. I require the PLC to: - Set/ Operate a (stepper or geard) motor to spin the spit in a clockwise and counterclock wise direction. - Set/ Operate a (stepper or geard) motor to raise and lower the spit. - Measure and display 2 anolog temperature sensor readings - Measure and display the speed from a tachogenerator - Contain programable "set time" operations - Contain display with time of day and other varibles. Can this be done? What limitations will I encounter? I would really appreicate some help Thank you
  12. Hi guys, I'm using Vision 130 PLC- V133-33-T38. When I'm using in the logic timers (for ex. TD), when I excite the timer, the time is not elapsing. I have created a coil itself...not working, then coil and contact...not working. I'm using simple network (for ex. when MB30 is 1, start TD4 (TD is set to time 10sec)). When time elapsed activate MB31. Simple as that. Does anyone has an idea why this is not working? Thanks,
  13. I've got some great news to share with you! Unitronics is proud to announce that UniStream has been nominated in Control Engineering's Engineer's Choice awards, in the category of Hardware: Integrated HMI Controllers. The Engineers' Choice Awards includes 29 categories of control, instrumentation, and automation products, revealing the best as chosen by Control Engineering's print and digital audience. If you would like to cast your vote, go to: http://ocreg.controleng.com/onecount/flexreg/displayform.cgi?g=0&form=369 We will be running another UniLogic training webinar, this time on the subject of Timers and Actions. This free webinar will be held on November 13th. Click below to register: https://www3.gotomeeting.com/register/269067086 On another note, Unitronics Support is setting up training schedules for the US, 2014. We have a proposed list of cities and would like to offer you the opportunity to let us know where you would like to see training held: http://survey.constantcontact.com/survey/a07e8gefzt7hnhg154m/a013lhnva2ir8/questions Finally, I'd like to invite you to join us on our Facebook page--it's a great way to keep updated with current Unitronics news http://www.facebook.com/UnitronicsUSA Have a good week--may all your programs be perfect :-)
  14. Just a quick post to remind you of the UniStream and UniLogic training videos. The newest addition is Languages--invest less than 5 minutes of your viewing time, learn you how to enable your users to switch the HMI display language by touching an HMI screen element.
  15. Check out the latest video--Languages. http://www.youtube.com/watch?v=4o-5VEYgiho&list=PLFBq_OH6_be7snAZAycZzQMvAWjHkX9Pz&index=13
  16. A_Mia

    VB .Net error

    All, I need to write to a timer preset and am getting an 'object' error using the .net driver. I'm sort of between a rock and a hard place... THanks in advance. Below is the 'function' that attempts to write - Public Function Write_TimerPreset(ByVal tmrIndex As Int16, ByVal TmrValue As integer) As Boolean Dim values As Object() = New Object(2) {} Try values(0) = DirectCast(TmrValue, Object) Catch System.Windows.Forms. MessageBox.Show("One of more of the values are not valid") Return False Exit Function End Try Dim wo As WriteOperands = New WriteOperands() With wo .NumberOfOperands = 1 .OperandType = OperandTypes.TimerPreset .StartAddress = tmrIndex .Values = values .TimerValueFormat = TimerValueFormat.SecondsFormat End With Dim rw(0) As ReadWriteRequest rw(0) = wo Try plc.ReadWrite(rw) Catch Dim ErrorMessage As String = "Could not communicate with the PLC" & vbCrLf & "Error # " & Str(Err.Number) & " was generated by " _ & Err.Source & vbCrLf & Err.Description 'Display the message as a critical message. MsgBox(ErrorMessage, MsgBoxStyle.Critical, "PLC Connection Error") CaptureErr(EquipmentPK, "Unitronics Class", "Write_TimerPreset", Str(Err.Number), Err.Source, Err.Description, Now(), EmployeePK, 0) Return False End Try Return True End Function
  17. 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
  18. 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.
×
×
  • Create New...