Jump to content

Search the Community

Showing results for tags 'unitronics'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • News and Announcements
    • Welcome to the Unitronics User Forums
    • New!
    • VisiLogic:9.8.64 - Link to mobile app, Ladder: 2x the Space!
    • New!!! ***** U90 Ladder*****
  • OPLCs and Application Software
    • Vision PLC series and VisiLogic
    • Jazz, M91 PLCs and U90Ladder
  • UniStream HMI + PLC and UniLogic
    • UniStream: Hardware
    • UniLogic Software
    • UniLogic UDFBs
  • 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

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 21 results

  1. Nice story here: Bimetec, a company specializing in agricultural solutions, used a Unitronics Vision1210 and a 4.3-inch Samba programmable logic controller for this retrofit project. Read about how they boosted speed and efficiency by clicking here.
  2. Hi I have Unitronics Jazz PLC Jz20-J-T40 PLC. When I connect to my PLC and make online changes, like forcing bit that changes my output, PLC shuts down. This bit that I force, turns ON pump on Output, and then I should get confirmation work signal on Input, but instead, it shuts down. When I'm not connected to PLC, and this same situation happens, it works normally, i can also see confirmation work on my PLC screen. But when I'm connected it shuts down on same place. I have 8 pumps that works this way, and same thing happens on all of them. Does my model of Jazz PLC can work in mode that I'm trying to work in (online debugging with I/O changing) or not? Please help. Thankful in advance, Nikola Ljubinkovic
  3. Hi I have Unitronics Jazz Jz-20-T40 PLC. I have all the newest software and PLC system. When i power ON my PLC, and then using USB i connect it to my laptop, connection is working fine and i can see PLC from laptop. Then, when I download PLC Program to my Jazz PLC, it downloads normally, and as it should, PLC reboots. On my other Jazz PLCs it turns ON again, and it's still connected to my laptop. But, on this specific model, when i finish download, and try to connect to it again, it displays 4-5 messages that says restart U90, PC and so on. When I try to connect to it again, I get same message. I tried to restart U90, still the same. I really don't want to restart laptop, so I tried to unplug and plug USB. It shows me that i don't have needed drivers for this device. I click update device software, it says it's already newest, as it should. Then i try to install from U90, it says that I already have it. Then I unplug and plug again, and everything works normally. Every time I download, i need to unplug and plug USB twice, before I can again debug my PLC. It just needs to be reconnected twice, without installing anything at all. It confuses me a lot. Please help. Thankful in advance, Nikola Ljubinkovic
  4. OPC Communication Slow

    Hi, I have two Jazz JZ20-J-T40 PLC-s, and one V130-J-TR20 PLC. I am using zView SCADA. I tried to connect them via Ethernet by using switch, but I cannot use two different PLCs on this SCADA. Then i tried to connect them to SCADA via uniOPC, but communicating is just too slow. I have just one bit that goes from 0 to 1 in 0.5 seconds, and back to 0 in 0.5 (1 second pulse), just for testing, still it's too slow. It runs normally for like 2,5 seconds, and then just stops, and changes in 4-10 seconds, or just freezes for 2-3 minutes, and then changes. My PC Spec are not in the way of this, I am sure of that, i have tried it on my weakest and strongest laptop, still exactly the same results, too slow with just one bit for each of the PLCs, that is 3 bits total. Does anyone had the same problem, is there a way of fixing this? Regards Nikola Ljubinkovic
  5. This was an excellent year - a year of growth - for the Unitronics community. We now number over 20,000 members! I can back this up with hard statistics for 2016: We welcomed over 3,000 new members to our user forum… …who made 2,100 posts … in 526 new topic! We all benefit from forum members who devote big blocks of time to helping others. These people put a lot of effort into writing detailed answers to questions and aiding others in trouble-shooting their applications. This year, three of our top posters from 2016 were again top contributors to the Unitronics community. Our top UniGuru MVPs for 2016 are: Joe Tauser Barry Lanier (forum name: Flex727) Ausman In recognition of their fine work, the profiles of our MVPs will be marked with a new icon for 2016: In recognition of their fine work, the profiles of our MVPs will be marked with a new icon for 2016: Our most valuable commodity is, always, time—to volunteer that time to help other people using your expertise is truly worthy of respect--thanks to you all! Youtube Channel The official Unitronics Youtube channel, https://www.youtube.com/user/UnitronicsWebinars is growing. In 2016, our top video clips were the: Webinar: HMI Tricks and Tips for VisiLogic, with over 8,000 views: https://www.youtube.com/watch?v=1MwhQkdbC6s PLC Training: Introduction to UniLogic, HMI + PLC Application Software, with over 6,000 views: https://www.youtube.com/watch?v=BV30MkDQYPk WEBINAR: Unitronics Vision - CANOpen, also with over 6,000 views: https://www.youtube.com/watch?v=iIkBJ4NheCc Media - We're in the NEWS! Unitronics was featured in a number of trade magazines in 2016—if you missed these articles, check 'em out now! IEN, Industry Interview feature: How Will Industry 4.0 Influence the Future of PLCs? IEN feature article. Hardware Division Benny Magrafta, Unitronics R&D Manager, Software Division, was extensively quoted: HMI checklist: What to consider when shopping for an HMI solution IEN - Industrial Products in Spotlight IEN featured an application based on the UniStream PLC + HMI, 10.4, a project done for Djurdjevic is a meat production company based in Serbia Is it possible for an automated system to run so efficiently you forget it’s there? We are proud to continue to bring you Unitronics true All-in-One value: our complete range of automation products and software from the pioneers of the PLC + HMI controller, backed by Unitronics unparalleled sales and tech support. Enjoy them in 2017!!
  6. ESTIMATED GOOD, I AM CONDUCTING A PROJECT THAT CONSISTS OF COMMUNICATING A UNITRONICS V120-22-R2C WITH A SCREEN REDLION G310 BY BUS RS485 ASCII PROTOCOL, THE SCREEN ALLOWS TO WORK WITH THE PROTOCOL OF UNITRONICS PCOM ASCII MASTER, I AM PERFORMING TESTS WITH THE V120 TO SEND DATA AND THE I GET THROUGH AN RS485 BUS EMULATED IN WINDOWS BUT I CAN NOT COMMUNICATE WITH THE SCREEN. E REVISED THE PARAMETERS OF COMMUNICATION, THE MAPPING OF VARIABLE ... AND NOTHING. I LEAVE THE TOPIC. GREETS CREATRIOS.
  7. Hi! I figured I may have run into trouble here and thought to ask for your opinion. I got my hands on Bautz DSK-12 AC motor driver and Unitronics Samba (4.3 inch, transistor type) PLC and acquaintance of mine asked me to do some programming. Firstly, I discovered that encoder (what I have to use) is running on 5v (actually to get encoder values from driver I have to feed it 5v and not any higher). Thought that I could buy fast (50kHz) optocoupler to ramp up 5v to 24v and feed it into PLC. Secondly, I discovered that this type of motor driver takes +/-10v to change motor direction and velocity. (ex. there is 2 pins, first pin has to have ZERO aka reference voltage and other pin has to have zero to +10v OR zero to -10v, accordingly which direction user wants to motor go). I do not have any thought how to fix this one. Do I have to order some kind of additional position controller or is there something else what can I do? Bautz DSK12 datasheet: http://www.ahs-antriebstechnik.de/pdf-dateien-e/Servo Drives Servo Amplifier/Manual DSK12-gb.PDF (German version, for german friends out there: http://www.servodyntechnik.de/DSK_12_d.PDF) Help from you guys would be greatly appreciated. Greetings, Steven
  8. Hello, I use the Unitronics V350-35-T38, where port 1 is RS232 and port 2 is the ethernet card. When I had setup GSM modem on the port 1 and I had tried to download the program to the PLC I had got a message that I had to change the firmware (OS) in the PLC to the version which support ProfiBus and dial function. So I did that, but then the ethernet card was unavaible. I need both - GSM modem and ethernet card. I tried this in the latest version of Visilogic. Then I tried 9.6 version of Visilogic because in the past we used both and we used this version. I do not know why now it is not possible. Could you help me? Thank you in advance.
  9. Hello mates! I have got a problem with CANopen connection between my Unitronics V560 and gateway Turck BL20-E-GW-CO. As u see on the picture I attached after connecting my PLC and Turck gateway Err red diode is turned on. In this case, user manual says: "Faulty or interrupted communication between BL20-CANopen gateway and other CANopen. Possible causes: – CAN-BusOff – Heartbeat error – Guarding error – Transmit timeout" "– Check that the fieldbus ends with a termination resistor, if the BL20-CANopen gateway is the last node in the bus topology. – Check the seating of the CANopen bus connector (or the joints in the case of direct wiring). All connections must be correct and properly seated. – Check the CANopen cable for possible damage, and for correct connections. – Check that the correct bit rate has been set. – Check that the NMT-master is still functioning properly." - I have turned on termination resistor (my gateway is first and the last one at once). I even added extra one to PLC between H and L signal. - My connectors seats well - Cables do not have any issues - Bit rate which I set in "COM PORT INIT" block is the same as in gateway - My master PLC (V560) works What can be issue of my problem? How could I cope with that? Thanks for your time. Cheers!
  10. Hello, My project involves filling a data table with real time data, and in order to progress through the experiment it needs to read the last 100 values recorded, sort them, and then get the resultant range. So I only need to read the last 100 values of the column I am currently fillling up during the program, but I only see a function that copies the entire row to a vector. This wouldn't work as the column has more numbers than the MI memory has operands. Is there any way to only put part of a column into a vector? Thanks in advance!
  11. 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
  12. Hello! I dont find enywhere; if unitronics macros for Eplan p8 even exist? I need Jazz, and all visilogic macros for Eplan. On "main" unitronics website i dont find it. Does macros even exsist??
  13. good fellow, I present below a video (in Spanish) of the application made ​​in cúcuta / Colombia. a counter tile production system where, thanks to a network of sensors installed you can post all production was implemented. part of this is calculated among other things: machine cycles lost time effectiveness square meter format produced break caused ton consumed in production lifespan of punches, dies Spaces within the furnace mimico of production in the end visualize all this is possible through web server sms OPLC email and scada done by my using dde excel and vba successes http://www.youtube.com/watch?v=ObB3oenmYFQ&feature=share&list=UUIDHP3ZVEBlfVoyINIjvqJw
  14. Unitronics Visilogic Training

    We know its the summer Holidays but looking forward we have some places on our next training course in September. 3 day Visilogic training starting on September 17th. Book early to avoid disapiontment. More information. "The course was great and the products are great too – I’ll try my best tomorrow to see if there’s any chance of trying to integrate these into the stuff we’re doing –it would certainly make my life easier!" MB (experienced PLC programmer). Many thanks for the training day. Really learnt a lot yesterday – I think the “stabilisers” have been taken off the bike – so I need to get some practise with this unit, and try to make it do a few things such as counting, and speed measurement ! DB (first time PLC user). Limited places so please contact us for more information.
  15. As has been noted elsewhere... Protective Lexan Covers are Now Available for All Vision Controllers. Even though the Unitronics Vision controllers are very economical, there’s no sense damaging them when you can easily apply a durable protective cover. We now offer a self-adhesive Lexan protective film custom cut for each Vision controller from Unitronics. This includes the V130, V350, V280, V290, V530, V560, V570, V1040and V1210. These protective covers are resistant to the following chemicals: Acetone, Methylene Chloride, Isopropyl Alcohol, Ethyl Acetate, Gasoline, Diesel Fuel, Coffee, Clorox3, Vinegar and more… AMPS currently has covers in stock to protect the V130, V350 and V570 controllers.
  16. My company, AMPS Industrial Controls, recently finished the installation and start-up on a control system for the Custar Stone Quarry project we mentioned late last year. This quarry is located in northwest Ohio and it supplies stone for road projects all over the region. We are pleased to say that everything went very well and the quarry is now up and running with wireless Ethernet communication between all three control stations. This was really a fun project so we would like to take this opportunity to explain it in some detail... Background – Unitronics Vision System With Wireless Ethernet from Westermo The stone quarry in Custar, Ohio is quite old. It has been crushing stone and providing northwest Ohio with rock for over 100 years! One problem, though, is that the numerous expansions and upgrades which have happened over the decades have resulted in control stations positioned all over the place. Our job was to integrate all the conveyors and crushers into one central PLC-based control system that could be operated from any location in the quarry. Ideally, this would be done wirelessly so as to simplify installation. Of course, reliability was a great concern. This quarry runs year-round and downtime is very costly. We must ensure that any breakdown in wireless communication would not result in shutting down the quarry. Safety was also a big concern. Great care would need to be taken to safely control crushing equipment remotely. AMPS Industrial Controls would also build the electrical control panels which must hold up to harsh outdoor conditions and be very reliable. We decided a control system based upon the Unitronics Vision line of PLCs would be a good solution. These controllers could be coupled with wireless Ethernet radio modems from Westermo to allow control from anywhere in the quarry. AMPS would handle the programming of the PLCs and would design the system to be reliable, easy to use and intuitive for the operators. Unitronics V570 to Control Main Operator Station The 5.7″ color touch-screen on the Unitronics V570 could serve as the HMI for the main control station. The new V1040 may have been an even better product but it had not quite been released when we started the job. This station is located at the highest point in the quarry inside a booth with a window so the operator can see everything that’s going on. It’s a small booth, though, so we didn’t want to take up too much space. The Unitronics V570 was a perfect fit. From this perch, the operator can control all the conveyors and crushers that wind through the quarry. In the photo below, you can see the main control station circled in red. Unitronics V350 to Control Other Stations The other two control stations only really required small HMI screens because the operators are not used as often. Most of the everyday control will take place from the main station. Because the large color touch-screens were not needed here, we selected the V350. Still part of the Vision series of controllers, the V350 provides full Ethernet capability with extensive I/O options but packaged with a smaller color touch-screen. The photo below shows the small booth where one of the V350 electrical control panels is installed. Not fancy but very nice accommodations in cold weather. Wireless Ethernet Communication Details The Westermo RM-240 was perfect for this application. These devices were easy to configure with a web browser. They formed their own WiFi network on site and were very reliable. The antennas were installed at each location and have been very reliable in all weather conditions. Each Vision PLC from Unitronics was installed with an Ethernet module to connect to the Westermo devices. Modbus IP is the protocol we used. I can’t speak highly enough of both the Unitronics and Westermo products. This control system has been in use for a couple months now and we haven’t had a single phone call from the customer. It is controlling every conveyor and crusher in the quarry. Even a crusher that draws 4,000 starting Amps! As always, it was nothing but pleasure working with the Unitronics Vision controllers.
  17. Increased Inventory

    Having analyzed our 2010 sales, looking particularly at areas of dynamic growth, we are increasing our inventory of Unitronics products. The increases will be seen mainly in the Vision Series of OPLCs but Snap I/O modules and Expansion I/O modules will also be increased. 2010 was a great year for us, in no small part due to the growth we saw in Unitronics sales. This is nice to see because it comes as a direct result of the strategy of increasing our presence on the web and emphasizing the quality, features and value of the Unitronics products. The control system design and electrical control panels side of the business has also been partly responsible for the growth so it is accurate to say our 2010 sales were balanced very well between standard control system components and electrical control panels. The Unitronics product line will continue to be one we emphasize in 2011 so we are in the process of ramping up inventory levels. This may take several weeks but shortly we will have a broad representation of V130, V350, V560, V570 and V1040 PLCs along with a good assortment of I/O modules on our shelf. Our goal is to fill orders for our OEM customers directly from our inventory and have all the most common PLCs available even if it’s not one currently used by one of our regular customers. Unitronics Vision, Jazz and I/O items we will stock include… V130-33-R2 V130-33-RA22 V130-33-T2 V130-33-TA24 V350-35-R2 V350-35-T2 V350-35-TA24 V560-T25B V570-57-T20B V1040-T20B V200-18-E1B V200-18-E3XB V200-18-E4XB V200-18-E5B V200-18-E6B EX-A1 EX-RC1 IO-AI4-AO2 IO-ATC8 IO-D16A3-RO16 IO-D16A3-TO16 IO-DI16 IO-DI8-RO8 IO-DI8-TO8 IO-RO16 EX-D16A3-RO8 EX-D16A3-TO16 GSM-KIT-41J V100-17-ET2 V200-19-ET1 JZ10-11-R16
  18. Twelve years ago when I started writing basic ladder programs for PLCs I made a lot of mistakes. Seemed like I was always getting halfway through a project only to realize I'd taken the wrong approach and needed to take two steps back before I could move forward. Frequently this resulted in me scrapping the entire program and starting over. I told myself that was fine. I was learning, right? Well... a dozen or so years later I'm still learning. Now I say, "You never want to stop learning," but I'm not sure I believe myself. I mean, wouldn't it be better to stop making mistakes, altogether? I suppose that's not likely to happen so here's the tale of my latest misstep:One of my projects for an OEM control system uses several data tables. Even though we've already built hundreds of these electrical control panels and the machines work great, we're constantly updating and improving the PLC/HMI program. Some of these changes affect the data tables. No problem, except...Two of the data tables are frequently accessed by a third-party wireless, handheld device called SynTrack. Here's where my mistake comes in: I should have put these data tables first in the list. Whenever you make a change to a data table, the starting location of all the data tables following it will change. The starting location of your first data table will never change, though, so it would have been a good idea for me to put one of these two first in the list of 7 or 8 tables. It wasn't a big deal to change this but there is an issue with the second data table that Syntrack needs to access.I can only have one table in the first position. What happens, though, when I make a change to the first data table? The starting location of table number two will change but I don't want to force changes to the software in SynTrack. An easy solution is to add a column in the first data table which holds an offset value to tell SynTrack what the starting location of table two is. SynTrack always knows where to find the first table and that first table will tell it where to find the second table. Simple but effective. Now I can make changes to any data table and SynTrack can keep up with my changes without the need to revise its software. I just need to remember to change the value of this offset integer.You can bet I'll remember this in future projects. It was aggravating to make the change this time around because changing the order of data tables required me to delete the originals and then search them all out in ladder, point to the new tables and then re-address all the fields in each of those DT function blocks.Hopefully my time-consuming mistake will help you, though.As always, I encourage you to stop by my primary website and visit my company blog where we regularly discuss Unitronics and other controls news.
  19. The Fascinating World of Twitter

    Well, I never thought it would happen but people have convinced us to enter the world of Twitter. We'll be tweeting often about Unitronics, control system design and the electrical control panels we build. We'd be honored to have you follow us @matthew_AMPS.
  20. 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
  21. 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.
×
http:///