Jump to content

dmurray

Members
  • Posts

    36
  • Joined

  • Last visited

Everything posted by dmurray

  1. I've been looking at implementing a CRio-style architecture for a Raspberry Pi 3, and I'd appreciate some feedback on what I currently have, and how I can improve it. My main aim is to get a solid architecture using mid-level techniques (say, CLD level) because most RPi users won't have much LabVIEW experience. Even CLD-level may be too much for a lot of people, but I think CLD level techniques are a minimum requirement for a decent architecture. I'm using the NI LabVIEW for CompactRIO Developer's Guide as a reference, although I don't have any embedded experience. Also, I use the Makerhib LINX library to interface with the RPi (available on VIPM). LINX running on the RPi is an embedded Linux application, although it's not real-time. Also, it's basically a headless application (you can't view FP's on a monitor connected to the RPi), although you can develop and run VIs in interactive mode i.e. view your front-panels on the development PC. The headless mode is ultimately how I want to use it anyway, with a TCP server on the RPi, and a TCP client on a PC/Laptop/etc. Another thing is that RPi running LINX only works on LabVIEW 2014. I'm using the Home edition as it gives access to the Control and Simulation package, plus MathScript (neither used in this architecture). The system in this example is very simple as shown below. The current architecture I have is also shown. The RPi simply reads the temperature and Alert signal of a PmodTMP3 sensor in a Main Processing Loop, updates the UI via another loop using CVT data, and turns an LED on if the temperature is above a set limit. Some points on the server/RPi side: The 'Main Processing Loop' is a sequencer which reads and writes the signals as mentioned above, but it also has a queue so commands can be sent to the RPi. Commands in the example are 'Set Temp Limit' and 'Set Temp Hysteresis'. These commands are sent by the client and processed by the TCP Receiver, where events are triggered for the Event Handler to add the commands to the Main Loop queue. I use CVT to pass relevant values between loops i.e. 'Main Processing Loop' -> 'TCP Send', and 'Main Processing Loop' -> 'UI Update'. I use STM for TCP functionality, as I find the Connection Manager makes life a lot easier. The TCP Sender sends data to any connected clients, the data being the temperature and alert values. Because of the embedded nature, standard button press functionality in events is not available on the RPi side, so to shut down the code in interactive mode, I use a Stop button and event in the Main Processing Loop. I use a global Stop value to stop loops when I want to close the program. This seems to be used a lot in CRIO applications. Any better solutions? I'd like to have the Main Processing Loop as a sub-vi so that I can tidy up the block diagram, but I can't work out how to do this (because of the Stop button used in the loop). As mentioned, standard events can't be used, and neither can references to FP controls (unless I'm missing something). Any suggestions on how to solve this? Same question for the UI Update loop. (Note it wouldn't be a problem in a headless application as I would have it free-running, and use commands from the client to shut-down the program). There's not much going on on the Client side: I have a TCP Receiver which updates the temperature and alert signal values on the client UI. I have an event handler which sends Temperature Limit and Hysteresis commands back to the client. So my general questions are, does anything really suck, any suggestions for improvement, etc. I also have questions on sharing the RPi connection resource so that I can have more than one processing loop (e.g. one for collecting data from the RPi, another for writing commands to the RPi), but I'll leave that for another thread. I've attached the code, but there may be an issue with dependencies. As mentioned, the code uses STM, CVT and LINX add-ons. Anything else missing should not be a problem in looking at the architecture. RPi Temperature System 1.zip PmodTMP3.lvlib
  2. Thank for the further insights, in particular JKSH for your post. I think your link to stackoverflow.com summarizes it for me as regards my OP: I'm a little bit wary about the comments regarding children inhibiting parent behavior, as I thought that definitely was bad practice. But I haven't come across any situation where I need to do that so I won't worry about that for now anyway. Thanks also for the insights in throwing exceptions when a method won't be over-ridden. That's something I was thinking about, so you've saved me a question. Cheers, all.
  3. Thanks for the replies, guys. (Thanks also for the links, ak_nz). That (mostly) clarifies things for me. ak_nz, I won't have a problem with children restricting the parent functionality if I do override the method at some point - I guess you're talking about LSP, right? One final question on this: once I put code in my abstract parent method, is it technically no longer called "abstract"? I can see that it doesn't matter functionally, but I just want to get my terminology right at this early stage.
  4. I have a fundamental question on HALs and abstract methods that I'd like clarified, please. In my HAL's up to this point I've been using a parent with abstract methods, implementing concrete methods in the concrete product(s) (see here for example), and using dynamic dispatch as appropriate to execute the concrete method. I think this is a standard technique and it works fine for me. Now I have another layer of abstraction I want to implement, but in this case the concrete products share a lot of functionality and often I can get away with just executing the same method for each product. Should I just go ahead and implement this logic in the parent method? If I do, that means I no longer have abstract methods in my parent (right?), so am I breaking some 'good-practice' rules in OOP design? Or am I just getting bogged down in semantics? [by the way, I have loads of little niggling questions like these which I may ask as I'm going along in my OOP learning - hope you don't mind.]
  5. Thanks for the reply. I probably haven't explained what I'm doing very well and turned it into a difficult problem, when probably all I'm trying to do is implement some simple messaging. Even the Template pattern is too elaborate, to be honest. I've been playing around some more, and currently what I'm looking at is using the "Start Asynchronous Call" VI to run in the background and scan for connected I2C Adapters. If the status changes e.g. if the number of connected adapters goes from two to one, or one to zero, this VI sends a message to the higher level, and the higher level makes a decision on what to do. For example it just checks to ensure that the adapter it is using has not been disconnected. I'm using User Events to achieve this. To be honest I don't really need this functionality in the HAL, as it just adds unnecessary complexity. But I'm struggling a bit with collaboration between objects in LVOOP and this seemed like a good opportunity to work through some of the concepts. I know there are a lot of good messaging threads on this forum but the discussion is often very deep and it's hard to pick out the fundamental techniques. So my new plan is to look through some of the implementations in the code repository to try and extract some of these fundamentals. Thanks again for the reply.
  6. Hi all.. I've been playing around with various HAL implementations for a while now, and I have a question on implementing some simple "state" functionality in the HAL. I've attached one such example - It's just an abstraction layer for a range of I2C Adapter modules that I use (or intend to use in the future). So my parent class is an abstract I2cAdapter, with overridable (dynamic dispatch) methods and exposed private data, effectively forming my interface to upper layers. Then at run-time I will just instantiate one concrete 'product'. (By the way, when I say "Adapter", it's nothing to do with the GOF pattern). Now I also want to add some simple "state" functionality, and I'm hoping to get some pointers on the best way to approach this. The states I can identify in the HAL are: 1. Adapter physically disconnected (i.e. plugged out from the PC/laptop/whatever). I want upper layer(s) to know that this has happened. 2. Adapter connected, and enabled (normal operation). 3. Adapter connected, but disabled. Effectively I want the adapter to be in a high-Z state as far as the bus is concerned. (Of course this should happen automatically for a 'true' I2C adapter when its not accessing the bus, but unfortunately I can't guarantee that with the devices I'm using.) I've looked at the GOF State pattern, but I think it's too elaborate for this situation. Also, I'm not sure it really applies here anyway. As I look at it, the Enabled/Disabled states can be done simply - just add one (or two) abstract method(s) in my parent class and let each concrete adapter implement the necessary functionality. But what's the best way to handle the Disconnected state? Should the concrete adapter implement some functionality and inform the upper layer if a disconnect has occurred? Or should the upper layer have some sort of a periodic check of connectivity? Maybe I should also add that one of the learning 'glitches' I'm having with LVOOP is the topic of collaboration between objects, and this post ties in with that to a certain extent. So any help would be appreciated.
  7. I need to think a bit more about reference use so. For now I think I'll use what's easiest, and think about the consequences later! Re. HALs: The blog post is very helpful. I'll think a bit more on this later, but for now I think a basic hierarchy is as shown below. For example, some devices will have both PMBus and SVID comms, some will be PMBus only, some will be pin-configurable and may need no other comms at all, etc. I also need to think about being able to add future devices and interfaces as simply as possible. In fact the serial-SVID comms approach I use is just prototyping work; I soon hope to add a better USB-type interface. Or maybe the hierarchy needs to be switched around: device families on the second layer, and interfaces at the third layer? Anyway, there's plenty for me to think about. I'll probably start a separate post when I have something more concrete. For now I really want to get back to looking at the ideas from last night. This has been very helpful for me, thanks again.
  8. Hi Matt, Thanks for the reply, there are some good points: This is a valid point - I accept that my fundamental code doesn't have a good 'OO' feel to it yet. My only exposure to OOP was in my university days a good few years back, and I can't really say I 'got' it then either. Although at the moment I am reading a couple of books on both OOP and design patterns; it's just that time is the enemy! In this case, there's definitely some commonality between the two interfaces, but they're also quite distinct (if that makes sense). PMBus has a much larger command set and handles most of the comms. SVID is a proprietary Intel interface with a much smaller register footprint in the device. And where they do share functionality, they tend to use different formats (for example a common task would be to read back the regulated load current, but there are subtle differences in how it's done in each I/F). But I'm sure there's a way to break down (combine?) the interfaces into a proper OOP structure; I just don't know enough yet to do it. I'm also thinking that maybe I need to have some sort of a HAL here (so that I can use the code with different devices?), but again I'm not sure how to go about it. I know there's a good white paper on HAL over on NI that I keep meaning to have a look through. It's just another thing on my learning list. Again, I just wasn't sure about the right way to go about things, but I understand a bit more now. I'll definitely start using controls as part of the class data now - obviously it makes a lot more sense (especially when it's pointed out to me!). I wasn't happy with all the FP references anyway, and they would have been a bit of a nightmare in the full app I have planned. I really like the Actor Framework but it's definitely beyond me at the moment. My plan over the next few months is to nail the fundamentals as much as possible, particularly some of the fundamental OOP concepts you mention. But I am thinking of using sub-panels in some way in my app; for example there are a lot of waveforms I could show, and I think it might be a good way to learn about sub-panels (I haven't used them before). I haven't even used User Events yet either, so I'm trying to think of a way to work those in without over-complicating things. But thanks for your reply, it is definitely helpful. Derek.
  9. Hi Elijah, Thanks for taking the time to reply. As it happens, just this evening I dug a lot deeper into your code (the Plugin Handler Command class in particular) and saw how you were passing data between loops and other classes, and I had quite a few 'A-ha' moments. Your replies clarified a lot for me too, so I don't have much of a follow-up: Yes, that was the plan, but I wasn't sure how to go about it, but as mentioned I think understand a lot more now. In fact, even if I wasn't going to share data I'd consider using the methodology as it's such a neat way to code. I'm definitely a fan. Okay, this sounds much better, I'll definitely implement this in some form. Okay, thanks for clarifying. I'm thinking now that I've never really used sharing between loops very well in my usual QSM designs. In one design, for example, I used a crude semaphore method to control access to a global log variable. Okay, makes sense. Like I said, even just the neatness of code makes me want to switch to OOP anyway. Thanks again for your help, it's much appreciated. Derek.
  10. Hi all, first post and I hope nobody minds that it's quite long. I've finally started to move into LVOOP and I'd really appreciate some help on the first example program I've designed. It's based on the Command/Factory pattern posted by Elijay_K on NI (I've even unashamedly adopted his color schemes for the loops!). I'm a bit wary that my questions will be too basic for this forum, but anyway, here goes... First, a quick description of the application I work with (see 'application.gif'): it's a digital voltage regulator which can be accessed by two interfaces, an I2C PMBus interface and a SVID interface (both are just digital power communication interfaces). In my program I just picked a few simple tasks to do (see 'front_panel.gif'): Read back basic info from the device (part name, FW version, etc). Carry out basic control of the regulator, such as setting the output voltage, over-voltage limit and switching it on. Read and write some internal registers. Continuously monitor a small sub-set of registers, and update a Vo plot. For the code, I currently have four loops: (1) Event handler to send commands to other loops, (2) PMBus communications loop, (3) SVID communications loop (4) UI Display loop to update front panel indicators (device info, monitored register values, 'power-good'/OVP fault). Note that the SVID loop has no real functionality yet; I just access the device using the PMBus interface. I currently have three parent classses, one for each consumer loop: pmbus_generic.lvclass, svid_general.lvclass, display_generic.lvclass. Then for each child class I just have an Execute method to carry out specific tasks e.g. read/write a register using the PMBus loop, update the plot using the UI Display loop. This brings me to my first question: (Q1) All my low-level functionality is carried out using legacy VI's (non-OOP) that I use as normal in my standard QSM architectures. So I found that I didn't need to define any data in the .ctl clusters for any class at all, yet everything works with no issues. Basically I think I have a dynamic dispatch OOP program which just contains methods but no private data at all. Is this okay? It works and all, but I feel like I'm missing something... (Q2) I just leave my 'UI Update' loop free-running, but this doesn't feel very elegant. In fact I have to 'Stop' that loop directly, and then use that event to stop all the other loops. Is there a more standard (OOP?) way to continuously update front-panel indicators in this sort of program? (Q3) I'd like to add some sort of logging functionality which takes information from both device interface loops- what's a good way of doing that? I'm thinking of using another loop and a related log class which receives data from the other loops. Is this the right approach or is there a better way? I'm assuming I need to be careful about one loop receiving data from two sources? (Q4) For the waveform plot functionality, rather than having it fixed I want a pop-up type window which will display a whole range of waveforms from the application. Do I need to go down the plug-in route here? (i.e. add a plug-in loop and class?). (Q5) I also want an Options dialog which I can pop up at run-time and change settings. Do I need another loop and class? Perhaps have it as part of any plug-in functionality? Or are there any other elegant config options I can use in OOP? (Q6) Just thinking, is the pattern I use here even the best choice? Is there a more standard pattern that I can use for what is really just a basic device-control GUI? Ultimately I want to code a much larger app which has lots more of the same functionality as this basic example, so I'd like to get the pattern right from the start. I've attached a ZIP file of the project, but there's probably a lot of low-level drivers missing; I don't think that matters (hopefully just the basic architecture is all anyone needs). Also, if I'm doing anything in general in the program that's completely idiotic, please point it out! And again, apologies for the length of the post. If it helps I don't really need detailed answers, just pointers in the right direction... Very Basic UI.zip
×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.