Current Component Name


Recommended Posts

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

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

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

  • 3 weeks later...
  • 2 weeks later...

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

 

 

 

 

 

 

Relay4_Sequence_Output.PNG

Relay4_Sequence.PNG

CreateProperty.PNG

Link to comment
Share on other sites

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

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

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

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

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

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

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

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

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

Archived

This topic is now archived and is closed to further replies.