PDA

View Full Version : trying to start off with scripting



Corsair8X
2nd March 2008, 08:46 PM
I'm really having problems wrapping my head around scripting. I sort of ripped off one and wrote one of my own (simple little things really) but I think that by not really understanding what's going on, I'm having some difficulties advancing to what I want to do.

The one that I ripped off was this:


//throttle pinky switch
timer(period, d2, 7) = js2.b4;
cms.b1 = d2 and not js2.b4; // FOV
cms.b2 = not d2 and js2.b4; // Autopilot overide


This works great (because I didn't write it). I even almost understand what is going on except for that last line. Let me explain in plain text what I think and where I am confused. Each line almost looks backwards to me. Is d2 a sort of name for the timer function? If that's the case, wouldn't it be "js2.b4 and not d2" ?

Could someone explain the plain english equivalent of what is being stated in that script?

But on to my real problem:
I have this code that I'm proud to say I did write after seeing how someone was attributing a similar line to something else. I made it work with the shift key (in this case, button 4 on my fs):



//view control
cms.b3 = (js2.b3 AND js1.b4); // TrackIR center
cms.b4 = (js2.b3 AND NOT js1.b4); // cycle between 2D and 3D pit


Works great. Now I'm trying to get it to do something else when I hold down the button for a short period of time (and not using the shift button I have.)

My lack of understanding led me to this, which is not working and probably not even close to what is required:



//view control
timer(period, d3, 7) = js2.b3;
cms.b5 = not d3 and js2.b3; // the thing that will happen when I press the button a little longer
cms.b3 = (d3 and not js2.b3 AND js1.b4); // TrackIR center
cms.b4 = (d3 and not js2.b3 AND NOT js1.b4); // cycle between 2D and 3D pit


I wonder if this is where an if statement is called for or something.

Thank you very much in advance for any help anybody can provide me. Even after just a little bit of scripting, I can see just how powerful this can be, and how you can combine a bunch of things on one button which is really cool.

Bob Church
3rd March 2008, 09:14 AM
Hi Corsair,

>> I'm really having problems wrapping my head around scripting. I sort of ripped off one and wrote one of my own (simple little things really) but I think that by not really understanding what's going on, I'm having some difficulties advancing to what I want to do.

The one that I ripped off was this:


// throttle pinky switch
//
timer(period, d2, 7) = js2.b4;
cms.b1 = d2 and not js2.b4; // FOV
cms.b2 = not d2 and js2.b4; // Autopilot overide

This works great (because I didn't write it). I even almost understand what is going on except for that last line. Let me explain in plain text what I think and where I am confused. Each line almost looks backwards to me. Is d2 a sort of name for the timer function? If that's the case, wouldn't it be "js2.b4 and not d2" ? <<

Sort of. It's not really a "name", it's just the bit that tells you what the output state is, but it is what you use to check the timer state so I suppose you could think of it as the name of the output of the timer. The timer itself really has no name, at least I've never given them one you could post here. :) When I originally wrote the the CM, it seemed like having a set of "device" bits would be a useful thing. Today, I'm not so sure that it really matters, that you couldn't have just used b1, b2, etc. but I'm not going to take them away. It would break too many scripts. Anyway, they're just bits that show the current output state of the timer.

WRT "not d2 and js2.b4" vs. "js2.b4 and not d2", they're equivalent, really. It's like the difference between "1 + 2" and "2 + 1", they both produce the same result. I think I probably wrote it that way early on just to keep d2 first and js2.b4 second, it was easier to keep track of which side the "NOT" should go on. I wouldn't think it would matter which way you did it.

>> Could someone explain the plain english equivalent of what is being stated in that script? <<

Sure. The PERIOD timer turns d2 on for a fixed amount time whether the input remains closed or not. Suppose the timer is set to generate a 1 second pulse on d2. That pulse will happen whether or not you hold the button down for a millisecond or an hour. You'll still get just 1 second on d2. So, if you press and release the button in less time than the PERIOD timer takes, when you release the button d2 will still be on, the button will be off, and so "d2 AND NOT js2.b4" will be TRUE from the time you release the button until the timer times out.

OTOH, if you hold the button down longer than the timer takes to run, d2 will go FALSE after 1 second and js2.b4 will still be TRUE. The "NOT d2 and js2.b4" will be TRUE from the time that the timer times out and d2 goes FALSE until you release the button. The net result is that if the button is down for less time than the timer takes, you get the "short click" output, if the button is down for longer than the timer runs, you get the "long click" output.

>> But on to my real problem:
I have this code that I'm proud to say I did write after seeing how someone was attributing a similar line to something else. I made it work with the shift key (in this case, button 4 on my fs):


// view control
//
cms.b3 = (js2.b3 AND js1.b4); // TrackIR center
cms.b4 = (js2.b3 AND NOT js1.b4); // cycle between 2D and 3D pit

Works great. Now I'm trying to get it to do something else when I hold down the button for a short period of time (and not using the shift button I have.)

My lack of understanding led me to this, which is not working and probably not even close to what is required:


// view control
//
timer(period, d3, 7) = js2.b3;
cms.b5 = not d3 and js2.b3; // the thing that will happen when I press the button a little longer
cms.b3 = (d3 AND NOT js2.b3 AND js1.b4); // TrackIR center
cms.b4 = (d3 AND NOT js2.b3 AND NOT js1.b4); // cycle between 2D and 3D pit

I wonder if this is where an if statement is called for or something. <<

It's hard to say. I'm not really clear on what you want to do, but it looks like you really want three stages, short, medium, and long, based on js2.b3. If you don't click it, the timer won't start and so d3 will always be FALSE unless you click js2.b3 first, so you're never going to see cms.b3 or cms.b4 unless you click js2.b3 to start the timer and then get js1.b4 down for the short or long click before the timer runs out.

If that's the deal, then it can be done, but it's difficult to code and use. Judging how long the midrange is while you're mind is on flying gets kind of difficult. An easier method (IMO) is one that is based on the number of click, e.g. 1 click is function 1, 2 clicks is function 2, etc.

I wrote a script a couple of years back based on that technique. Basically, it starts an OFFDELAY and then counts the clicks until you stop clicking for some preset period of time. It's more responsive in that the time it waits after the last click can be short, where the setup you were using or anything based around that fixed PERIOD timer doesn't actually respond until the timer times out so it always takes half a second or whatever to respond. With this one you can reduce the time in the OFFDELAY until it gets uncomfortable. I've got it set for a quarter of a second in the one below, but you can play with the value until it's comfortable.

This was the script. It's set up to respond to clicks on js1.b2 (I don't have a js2 running right now) but otherwise I tried to match it up with what you were using. If it sets up any conflicts with other parts of your script, you'll need to sort that out. It generates one of three outputs on CMS Controls buttons 3, 4, 5. Anyway, here it is:


script

// Turn all the outputs off on the next click of the character clock
// to reset them for next time.
//
if( CLOCKTICK ) then
cms.b3 = FALSE;
cms.b4 = FALSE;
cms.b5 = FALSE;
endIf

// Start or restart an OFFDELAY of 1/4 second whenever the button
// is clicked.
//
timer( OFFDELAY, d4, 5 ) = js1.b2;

// Generate a very short pulse (1 scan) when the button (js1.b2)
// is clicked and the OFFDELAY is still running.
//
pulse( d5 ) = js1.b2 AND d4;

// See if the OFFDELAY is running and the button and the button
// clicked, increment the click counter (a1).
//
if( d4 ) then

// It's still running, so if the button clicked, increment the
// counter to a maximum of 3. You can expand the maximum number
// of clicks if you need 4 or 5 or even 1000, but this one just
// does three.
//
if( d5 AND [ a1 < 3 ]) then
a1 = a1 + 1;
endif

else

// The delay has timed out. If any clicks are in the counter
// set the output that corresponds to the desired function, and
// clear the tick counter.
//
if([ a1 > 0 ]) then
cms.b3 = [ a1 == 1 ];
cms.b4 = [ a1 == 2 ];
cms.b5 = [ a1 == 3 ];
a1 = 0;
endIf
endIf

endScript

It's easier to do than the timed method and easier to control, maybe it will do the trick for you. If you try it and have any problems, let me know!

Best regards,

- Bob

The StickWorks
http://www.stickworks.com

Corsair8X
3rd March 2008, 07:15 PM
Hehe, I guess I'm still not getting it. Let me ask the first question a different way with some information that you have provided.



timer(period, d2, 7) = js2.b4;
cms.b1 = d2 and not js2.b4; // FOV
cms.b2 = not d2 and js2.b4; // Autopilot overide



You mentioned that they are essentially saying the same thing, 2+1 vs 1+2. My problem with understanding is that with the math problem both answers equal 3, yet in this case both lines produce different results. In that case I would expect both cms.b1 and cms.b2 to go since the answer would be the same. Yet it does not. So what is different?

The Real Problem
I should have explained what it was I was trying to do :blush:

I have one button (js2.b3) that I want to do a bunch of different things. If I press it simply, then it will go through this list of stuff, one thing at a time. However, with list you lose the ability to shift something, so when I press my shift button (js1.b4) and the js2.b3 button, I want it to do something else. However, if I press and hold js2.b3 for a short period, I would like it to do something else. So that is what I am trying to accomplish. I should have just mentioned that in the first place rather than dump a bunch of
code and expect someone to know what was going on :blush:.

Bob Church
3rd March 2008, 11:47 PM
Hi Corsair,

>> Hehe, I guess I'm still not getting it. Let me ask the first question a different way with some information that you have provided. <<


timer(period, d2, 7) = js2.b4;
cms.b1 = d2 and not js2.b4; // FOV
cms.b2 = not d2 and js2.b4; // Autopilot overide


>> You mentioned that they are essentially saying the same thing, 2+1 vs 1+2. My problem with understanding is that with the math problem both answers equal 3, yet in this case both lines produce different results. In that case I would expect both cms.b1 and cms.b2 to go since the answer would be the same. Yet it does not. So what is different? <<

My mistake, actually. I thought you were talking about one of the two lines being written in two different ways, e.g. "not d2 and js2.b4" as opposed to "js2.b4 and not d2". The two separate lines do produce different results because the "not" switches from one variable to the other.

It's the timer that sets it up. A PERIOD timer turns on immediately and stays on for the defined length of time specified in the timer statement whether you hold the button down or not. In the above, as soon as you click js2.b4, d2 turns on for about 350 milliseconds (7 * 50 assuming you've got the character rate set to the default 50 milliseconds). Which output it generates depends on when you release js2.b4, either before or after that period has elapsed.

Both statements produce FALSE initially. In the first one, cms.b1 is FALSE because d2 is FALSE (you haven't started the timer yet). cms.b2 is FALSE because "NOT js2.b4" is TRUE (the button isn't pressed). Nothing happens until you press the button.

After that it's a horse race, really. Do you get your finger off the button before the timer runs out or does the timer run out before you release the button. If the button wins, cms.b1 turns on because d2 is still TRUE and "NOT js2.b4" (the button is released) is also TRUE. The output will come on, but only until the timer runs out, so you get a pretty short pulse.

OTOH, if the time "wins" then cms.b2 turns TRUE since js2.b4 is still TRUE (the button is down) and "NOT d2" is also TRUE (the timer has timed out, d2 itself is false. It will remain TRUE until you release the button, so if you do have to have one of them be the shift button, it has to be the long side. It's the one that stays down. You just have to make allowance for the fact that the shift button is a little laggy. You need to hesitate long enough to let the timer to run out before trying to execute the shifted function. That's all the cms.b2 side is actually, an ONDELAY. It's just being set up by inverting the PERIOD timer. If you think about it, an ONDELAY timer is nothing more than an inverted PERIOD timer.

>> The Real Problem
I should have explained what it was I was trying to do

>> I have one button (js2.b3) that I want to do a bunch of different things. If I press it simply, then it will go through this list of stuff, one thing at a time. However, with list you lose the ability to shift something, so when I press my shift button (js1.b4) and the js2.b3 button, I want it to do something else. However, if I press and hold js2.b3 for a short period, I would like it to do something else. So that is what I am trying to accomplish. I should have just mentioned that in the first place rather than dump a bunch of code and expect someone to know what was going on. <<

Okay. You say you want it to do "something else" if it's shifted. It's what that "something else" is that's the problem. It would be easy enough to simply redirect js2.b3 based on the shift button:


script
cms.b1 = js2.b3 AND NOT js1.b4; // cms.b1 is js2.b3 unshifted
cms.b2 = js2.b3 AND js1.b4; // cms.b2 is js2.b3 shifted
endScript

The unshifted side sounds like it could be handled with List Mode programming if it's just characters, or you could reference it down in the script itself to advance a SEQUENCE. If you do just need to put a character or button on cms.b2, remember that it's shifted at the time, so you have to put NULL in the "Normal" box amd program the shifted side.

Anyway, it's that "something else" that's probably going to determine what you need to do. I don't know if any of that's any help. Let me know what sort of thing the "something else" is and I can probably give you a better answer.

Best regards,

- Bob

The StickWorks
http://www.stickworks.com

Corsair8X
4th March 2008, 02:26 AM
That first analogy makes a lot of sense. I had wondered why the not would go before the d2 in that case, I just did it because that's what was in the code that I found. Now I actually understand - "not d2". I think I get it!

Back to the real problem:
The something else I eluded to would be just a character. Essentially for flexibility I was thinking of just tying another csm.bx to it. It could even be another list. In the end, just activating another cms item probably makes the most sense. It may or may not be the most efficient method, but I think it's something I can get my head around for now.

So to further flesh out my desired function, let's just say that simply pressing the button (js2.b3) activates cms.b1. Pressing and holding for a short time activates cms.b2. And Pressing the button along with my shift button (the common js1.b4) activates cms.b3. I think that may get me where I want.

My main reason for this is because when you check the "list" box you can't then use shift in the gui. However, I also want to have a delay feature as well and thus get about 3 functions out of the same button if possible.

And thank you for all your help thus far. I have a much better understanding of that timer feature. Hopefully that will lead to better things in the future.

Bob Church
4th March 2008, 10:43 AM
Hi Corsair,

>> That first analogy makes a lot of sense. I had wondered why the not would go before the d2 in that case, I just did it because that's what was in the code that I found. Now I actually understand - "not d2". I think I get it! <<

Ah. Yes, it's really fundamental. It just inverts the state of whatever it's assigned to, TRUE becomes FALSE and FALSE becomes TRUE. It doesn't necessarily only apply to the next bit. It does here, but if you were to write:



cms.b1 = NOT( js1.b5 OR js1.b6 OR js1.b7 OR js1.b8 )


it would get applied to the result of all the logic between the parentheses. Assuming a FighterStick, that example would turn cms.b1 TRUE whenever Hat 1 was in the middle. If you were to remove the NOT, it would turn it on whenever Hat 1 was in any position other than center. It does look kind of odd stuck at the front of the line like that, but it makes perfect sense to the computer. You just have to be sure you know what you're applying it to. The operation itself is really one of the most basic, it shows up a lot.

>> Back to the real problem:
The something else I eluded to would be just a character. Essentially for flexibility I was thinking of just tying another csm.bx to it. It could even be another list. In the end, just activating another cms item probably makes the most sense. It may or may not be the most efficient method, but I think it's something I can get my head around for now. <<

Don't worry too much about efficiency, really. The machines are so fast today that it's hard to make a serious dent unless you do something wrong. Anyway, the first thing is to get it to work. Even if it's a little slow, it's working. You can always come back and look at the individual pieces and try to get them to run more efficiently if you need to, but I've never much worried about it. When I first go into all this, it was reading gameport, and the time it spent processing the information was a significant part of the code. By the mid-90s, the machines were fast enough that the limiting factor was really the time to access the ISA bus itself. It took about 1.25 microseconds to get the data back from the thing (at least, that was about as fast as I was ever able to get it to run). When the went ot the game ports on PCI sound cards, the raw values coming back just about four-fold. Anyway, don't worry about it until you have to. I've got an old benchmark program. It shows a speed of one on the original IBM PC. I know it's not accurate on todays machines, but the AMD Athlon64 3000+ gives me a value of 62,000+. It makes a big difference in how you look at coding. Used to be, I felt guilty if I spent 256 bytes on a joystick routine. Now I'm happy if it fits on a CD. :)

>> So to further flesh out my desired function, let's just say that simply pressing the button (js2.b3) activates cms.b1. Pressing and holding for a short time activates cms.b2. And Pressing the button along with my shift button (the common js1.b4) activates cms.b3. I think that may get me where I want. <<

So, a short click on js2.b3 goes to cms.b1, a long click goes to cms.b2, and a shifted click on js2.b3 goes to cms.b3? Sure, that's easy enough. To start with, you know the short/long differentiator logic, so we can begin with that. Just from experience, and from the fact that I'm going to go through this about 3 times here, I'm going to set up some flags at the beginning. The b1 bit will be TRUE to enable the entire logic block, b2 will be TRUE if just js2.b3 is pressed, and b3 will be TRUE if both both js2.b3 and js1.b4 are pressed (it's shifted). It will simplify things later.

Start with the "blue sky" case. By that I mean nothing ever goes wrong (fat chance). You always remember to press the shift button first if it's a shifted function and you always wait until the operation is complete before trying to do it (or another of the functions) again. Get it running first, then deal with the little problems one by one.

I came up with this. I think it does what you described, maybe it will get you started. It looks like this:


script

// Set up a bit for unshifted JS2.b3, saves some typing
//
b1 = js2.b3 AND NOT js1.b4;

// Likewise for the shifted JS3.B3
//
b2 = js2.b3 AND js1.b4;

// Now set up the long/short differentiator logic
//
timer( PERIOD, d4, 7 ) = b1;
cms.b1 = d4 AND NOT b1;
cms.b2 = NOT d4 AND b1;

// And finish it off with something simple. The b2 bit is already
// what we want so just pass it through to the output.
//
cms.b3 = b2;

endScript

It has a problem if you release shift in the middle of the command while you've got js2.b3 held. It's starts the unshifted short/long deal. If you hold js1.b3 and shift, you get cms.b3 okay, but if you release the shift and keep holding js2.b3, it will either generate a long-press function, or if you briefly release it and press it again, it produces a short-press function. I don't know if those would be a problem or not. The could undoubtedly be interlocked if it does though.

If you wanted to do a sequence, you'd need to lock it out until the sequence is finished, probable set some lockout bit when the sequence start, clear it at the end of the sequence, and use it to lock out other functions while the sequence is running. It all just depends on what you need to accomplish. Anyway, I think it does essentially what you were asking for, maybe it will help get you started and then we can see what needs to be changed.

>> My main reason for this is because when you check the "list" box you can't then use shift in the gui. However, I also want to have a delay feature as well and thus get about 3 functions out of the same button if possible. <<

I gave a lot of thought to that when I was setting it up, but it was just too unpredictable. You would have to switch to the unshifted function first then shift it, or you'd have to shift first and then switch into the function. In either case you'd see two functions and it would get messy.

>> And thank you for all your help thus far. I have a much better understanding of that timer feature. Hopefully that will lead to better things in the future. <<

You're quite welcome, Corsair! I'm always glad to help!

Anyway, give it a try and see what you come up with. If you hit a wall, just come on back and ask, it can probably be worked out.

Best regards,

- Bob

The StickWorks
http://www.stickworks.com

Corsair8X
4th March 2008, 02:42 PM
I haven't had a chance to try this because I'm at work but I just had to read it :)
What surprises me about what you wrote is the simplicity of it. I think I even understand it :) Essentially declaring your variables at the start (excuse me while I explain it using my feeble understanding of javascript terms), in addition to likely creating less to type also makes it readable to a noob like me. Now that I sort of know how the timer function works, the rest of it kind of falls into place.

Thank you very much for your help. Once I get a chance to sit at my computer again I'll test it out. I suspect that this will work great because I'm not trying to do anything too crazy, and this script doesn't look crazy either.
:cheers:

Corsair8X
9th March 2008, 05:13 AM
Naturally work got busy and I couldn't get back to this until now. I had to take some time to understand this again, but I'm kind of glad for the delay because it forced me to have to look at this fresh and dissect it over again. I think that has contributed to a better understanding for me.

In the end, it works like a charm. Just as I expected. I'm also hoping that my renewed understanding of it will help me do more in the future. This is pretty powerful stuff because it really allows me to tap a few things into a button should I need to. I'm trying to avoid the modes at this time because I don't think it works with my style anymore, especially with all the MFPs I have.

Thank you very much for your help and patience. I had a lot of questions I know - and we had to go over some territory more than once. This was because I wanted to do more than just have a script that worked, but if possible, understand it. I think I actually do and now I'm more impressed with scripts than intimidated by it. Again, thank you for your help - and your work to make these controllers so powerful.

Bob Church
9th March 2008, 09:38 AM
Hi Corsair,

Well, you're really quite welcome. It can take awhile to come to grips with the scripting, but it does get easier after you've done a few of them.

Anyway, I'm glad it's all working for you. If you run into anything and need some help. just ask away.

Best regards

- Bob

The StickWorks
http://www.stickworks.com

Ziggy
13th March 2008, 01:17 AM
OK, I did actually write this script but Bob has already hit the nail on the head here...



After that it's a horse race, really. Do you get your finger off the button before the timer runs out or does the timer run out before you release the button.


What I wanted from this particular button was dual functionality without the need for a shift command or (worse...IMHO) a mode change.

A single click will change the FOV but when the button is held down it overrides the autopilot or terrain following radar. This allows the pilot to make adjustments without having to use a whole bunch of switches to disengage then re-engage the AP. Especially handy when in TFR mode. In the F-16 (and on the Cougar) we have an extra paddle switch for the latter but sadly lacking on the Fighterstick so by using this script I managed to combine both of these features in one button. I used the pinky switch since the paddle is located near near to this one (and also operated using the pinky).

This script is also fairly tolerant regarding the actual delay timer value since AP override is a button generally held down for extended periods of time, at least relative to the FOV change which operates on a click basis.

Finally, even if the button is held too long for FOV function, inadvertantly activating the AP override at this point is hardly going to ruin your day.