Rodney Posted December 30, 2017 Share Posted December 30, 2017 Hi is there a variable that identifies the Current component name? I have 4 Knob components on the one page named Relay_timer1 Relay_timer2 Relay_timer3 Relay_timer4 I would like to call a function via an event and pass the the numeric value of the component name as a variable based on what component knob is "in use" this leads to a second question - is there a simple way to strip the alpha characters from "Relay_timer1" to return "1" etc Rodney Link to comment Share on other sites More sharing options...
AzeoTech Posted January 2, 2018 Share Posted January 2, 2018 No, there is no way to get the name from within the component, but that would be a nice feature, so please post to our feature request section and we'll look to add it. Instead of naming the components, instead try creating a property using CreateProperty (7.15 in user's guide) that holds the knob #. You can edit these properties from the docking Properties window. Properties are accessible from component events (and globally using component.myName.propertyName). There are several ways to get the number off the end. If you know the number of digits, then you can just use the right() function. You can maintain a constant # of digits by prepending 0's, so 1 becomes, say, 01 so that you can do right(myString,2) and get a valid #. That would get you 100 combinations. If you know the last non-numeric character, you can use reverseFind(), in your case: reverseFind(myString, "r") to get it's index, the use mid() to extract everything after it: strToDouble(mid(myString, reverseFind(myString,"r") + 1, 1000)) Link to comment Share on other sites More sharing options...
Rodney Posted January 3, 2018 Author Share Posted January 3, 2018 Thanks I will try the CreateProperty option as suggested the right() string function will work for me Link to comment Share on other sites More sharing options...
Rodney Posted January 4, 2018 Author Share Posted January 4, 2018 Instead of using CreateProperty function I have attempted to use the existing OnPaint and OnChange properties for the 4 different knobs with limited success I set the variable "timer" to 1 2 3 or 4 in the OnPaint property depending on which Knob component it is I then call the sequence to run in the OnChange property The problem I have is I have to set timer variable as global for it to work I need it to be either private / local to that Knob component so that the sequence uses the value assigned to the Knob component its running from Is there a way to achieve this? Link to comment Share on other sites More sharing options...
SteveMyres Posted January 26, 2018 Share Posted January 26, 2018 Wow, what a very cool and powerful feature! Extensible components. As long as I've been working in DF, I never knew this was there. Thank you! Link to comment Share on other sites More sharing options...
AzeoTech Posted January 29, 2018 Share Posted January 29, 2018 OnPaint is fine, but you still want to use CreateProperty() in OnLoad() to create a local variable to the component. Link to comment Share on other sites More sharing options...
Rodney Posted February 12, 2018 Author Share Posted February 12, 2018 Hi well I got this to work but by a bit of luck rather than good coding I think please see attached I think I have misunderstood your instructions in your post of January 3rd in the on load event for each knob I created the timer property and set its value to either 1 2 3 or 4 depending on which knob it was for each sequence I set the private timer variable to either 1 2 3 or 4 ( I have attached Relay_Timer4 as an example) the Sequences works - when I change the value on the knob the relay opens knob color changes then once the time expires changes color and the relay is closed I can get this to work for all 4 knobs and they do run concurrently without any issues I would like to run this as a function with only one sequence that is passed the argument of the timer value 1 2 3 or 4 this is where I can see my coding fails I cannot seem to pass timer value to the function sequence ( by substituting the private timer = "x" ) on page 153 of the manual it says Initial Value is the value assigned to the property when it is first created. Once the property is saved with the document, the initial value, and for that matter, this whole function call, is ignored, as the document loading will create the variable and initialize it. I think I'm trying to initialize the timer value 4 times which obviously is not right what do I need to do to achieve my goal of passing the correct value to the function? once this is solved I plan to use the startthread function (even though in an earlier post you said it might be beyond my programming skills I think I can get it to work) I have a couple of big picture questions re startthread my project has these 4 timers per site and there could be 20 sites which in theory could have 80 threads running at once - ! have no idea what limits DF has - I'm guessing it's processor / ram related - am I being too ambitious? (excuse my complete lack of knowledge here...) Secondly in the manual re startthread the last line says the function call must be a string Example: StartThread("MyFunction(x,3)",MyThread,5) Note that the function call MUST be a string. My question is - can execute /evaluate be used to generate the "MyFunction(x,3)" and the"MyThread" strings or must they be a strings? Rodney Link to comment Share on other sites More sharing options...
AzeoTech Posted February 14, 2018 Share Posted February 14, 2018 You set Timer to 4 in the sequence function. I think you want to replace that first line with: function relay_timer4(timer) and then call from the component using: relay_timer4(timer) (the two "timer"s in my code are only because you named the variable the same. The value isn't passed because both "timer" was used in both places, but rather because of how I declared the function relay_timer4) That said, you wouldn't want to call Relay_timer4 from within a user interface component because it has a loop and will hang DAQFactory. Things inside component events, or actions have to be fast as the entire user interface blocks while that script runs. This means basically that DAQFactory appears hung until it is complete. As to your other questions: The # of threads in DAQFactory is PC limited, not DAQFactory limited. 80 threads is not a problem. It may not be terribly efficient as task switching is expensive, but that probably doesn't matter in your case. You don't need execute or evaluate to set the first StartThread() parameter. That's a string, so you can build that dynamically. As for the name of the thread, I would just make it so you can stop the thread from within the sequence itself. For example, you could have an array that contains a running status: global myThreadRunning = fill(0, 80) Then right before starting the thread, set the appropriate array element to 1, then pass the index for that array element to the function. Then, inside the loop inside the function you started in its own thread, just check the appropriate element and return() if it goes to 0. That all said, be careful with StartThread(). If you mess up you could easily end up making thousands of threads instead of 80, especially when first debugging. I personally only use StartThread() inside of objects using the StartLocalThread() function. This function is just like StartThread(), except can only be called within a user object / class. The thing about it is that once the object is destroyed, any running threads it created are also destroyed. Since objects are automatically destroyed once there are no longer any references to them, they clean up a lot nicer than threads started with StartThread(). Your application really sounds like one for object oriented programming anyway... Anywhere where you have lots of things that are essentially the same should be in objects. Link to comment Share on other sites More sharing options...
Rodney Posted February 16, 2018 Author Share Posted February 16, 2018 Thanks for the reply - understood re not calling the function from the user interface component I need you help with the logic / syntax- my thought is to set a flag from the user component and read this flag from my data acquisition / write sequence as it loops through it checks if false skip if true call the function however my logic falls down in that when the flag is true it will call the function again continuously - leading to the issues with multiple threads you highlighted Whats the simple way to call it once only once the flag is set? one final thing in your post - you say objects are "automatically destroyed" - as I am a non programmer could you please explain this a bit further - I am guessing after a function / sequence ends all variables components that are not global etc are "flushed" from memory - is my interpretation somewhere near the mark? Link to comment Share on other sites More sharing options...
AzeoTech Posted February 16, 2018 Share Posted February 16, 2018 You just need to clear the flag in the code that is processing it. So, set the flag to 1 in the screen component, then when the sequence processes that flag, set it back to 0. Yes, private variables are automatically "flushed" from memory when the sequence ends. When an object is created using new() you will always assign it to a variable. If you don't the object is destroyed as soon as that line of script is complete. But the object isn't really stored in the variable, just a reference to the object, sort of like the objects phone #. If you then do: myNewVar = myObjectVar or you pass that variable reference to your object to a function, you aren't actually copying the object, you are simply passing the reference to the object, the phone # in my example. Script can then use that phone number to actually get to the object and do things with it. Well, as variables go out of scope, or you assign new values to variables, the phone # of a particular object may get lost. If all the references to the object are lost, the object is automatically destroyed since there is no way for any script to access it anymore. There are really two ways these object references are lost: 1) a variable goes out of scope (private variable being destroyed at the end of the sequence, local variable in object destroyed with the object, and 2) when you assign a new value over top of the existing reference. Link to comment Share on other sites More sharing options...
Rodney Posted February 21, 2018 Author Share Posted February 21, 2018 thanks - the logic is so simple....... I got the startthread to work however I have missed fundamental issue with Functions / startthread as they call as a function which runs in the calling sequence thread not in their own thread.... it stalled my sequence until the startthread function completed This means my hope of using startthread will not work as I have to get the timer sequences running concurrently However a small logic change to use Beginseq instead would solve my issue I think My question is Can the same sequence be called from different threads and run concurrently in its own thread? -please see attached color coded PDF Site1_poll calls Site_Poll and runs in Thread A (yellow) Site2_poll calls Site_Poll and runs in Thread B (yellow) can I call Relay_Timer1 sequence via Beginseq to run in ThreadAa (blue) and call it again via BeginSeq from Thread B (yellow) so it runs in Thread Ba (blue) concurrently? (with it own set of variables of course) If so my issue is solved and in theory I could have my 80 threads all running at the same time (realistically it may only be 5-10) Multiple_Seq_Func.pdf Link to comment Share on other sites More sharing options...
AzeoTech Posted February 21, 2018 Share Posted February 21, 2018 Yes. I actually will do that if I don't want to get into objects. So, for example, I might have a sequence called "PollDevice" that takes an ID: function pollDevice(id) // poll the device with id Then, create, say, 4 other sequences, pollDevice1, pollDevice2, etc. that simply call pollDevice() with a different ID. Then I start the pollDevice1, 2, 3, etc. as a sequence in their own thread using beginseq(). All of them call the same pollDevice sequence function, but pollDevice is never actually marked as "Running" because it is called from pollDevice1, 2, 3, and 4. Link to comment Share on other sites More sharing options...
Rodney Posted February 21, 2018 Author Share Posted February 21, 2018 Thanks just need some clarification I understand I can call polldevice1 polldevice2 etc - from say my Thread A in the PDF however can I call polldevice1 again from within a different thread - My Thread B in the PDF it means that polldevice1 has been called twice and is running concurrently in its own 2 separate threads (Aa and Ba in my PDF) Link to comment Share on other sites More sharing options...
AzeoTech Posted February 22, 2018 Share Posted February 22, 2018 Yes if called as a function, but you can't do: beginseq(pollDevice1) and then do it again. If you do beginseq() on a sequence that is already running, nothing will happen. Link to comment Share on other sites More sharing options...
Rodney Posted February 22, 2018 Author Share Posted February 22, 2018 ok understood as I need to run all these concurrently in separate threads I would need (potentially) 80 different 1 line sequences to call the function is there a way to generate a sequence via script? Link to comment Share on other sites More sharing options...
SteveMyres Posted February 23, 2018 Share Posted February 23, 2018 But I thought calling as a function would not spawn a new thread. Link to comment Share on other sites More sharing options...
AzeoTech Posted February 23, 2018 Share Posted February 23, 2018 Rodney: yes, I described it in my post of Feb 13. Steve: correct. Calling as a function runs the code in the thread of the calling script. But unlike starting a sequence with beginseq(), calling as a function is reentrant, so the code can be run simultaneously if called from different threads. It also means you can call sequences as functions recursively. Note that StartThread() is not limited to one per sequence function. Link to comment Share on other sites More sharing options...
SteveMyres Posted February 23, 2018 Share Posted February 23, 2018 Ok, so in short, what you're saying is to generate n threads first, and then call the desired sequence from within them. Link to comment Share on other sites More sharing options...
AzeoTech Posted February 23, 2018 Share Posted February 23, 2018 It depends. If you are using StartThread() you can just call the desired sequence directly from StartThread(). But if you don't want to use StartThread, which is definitely more advanced, you can create multiple sequences, each which call the same other sequence as a function with a different parameter. Then you can start those sequences and basically have your function run simultaneously in multiple threads under multiple parameters. It's the simpler way, but when you have a lot of threads, you should use StartThread(). As I said, you probably actually want to use StartLocalThread() within an object so that the thread is garbage collected. Link to comment Share on other sites More sharing options...
Rodney Posted February 23, 2018 Author Share Posted February 23, 2018 Steve - you have hijacked my post!! As a non programmer this is great - I'm learning all the time.... Guru - not sure if you have actually answered my question - can script generate and save a sequence? Rodney Link to comment Share on other sites More sharing options...
AzeoTech Posted February 23, 2018 Share Posted February 23, 2018 I did answer it, a few weeks ago. Look at my post from Feb 13. I think you are confusing terminology. A sequence is just script that can be run in its own thread. Link to comment Share on other sites More sharing options...
Rodney Posted February 23, 2018 Author Share Posted February 23, 2018 thanks - let me reread your answer - sorry.... Link to comment Share on other sites More sharing options...
AzeoTech Posted February 23, 2018 Share Posted February 23, 2018 No worries. It just helps to think of a sequence as simply a container that holds script. You can access that script by either calling it as a function, or by "starting" the sequence, which creates a thread and then runs the script in that thread. The advantage of using sequences for your threading is that it is really obvious what threads are running, and you can easily start and stop them. BUT, it's not particularly scalable, and that is where StartThread(), or better StartLocalThread() are used. Link to comment Share on other sites More sharing options...
Recommended Posts
Archived
This topic is now archived and is closed to further replies.