Need help optimizing a script

GPC2 script programming for Titan Two. Code examples, questions, requests.

Re: Need help optimizing a script

Postby Fenria » Fri Feb 08, 2019 2:41 pm

Thanks for adding in the function cycling feature.


Are the 2 additional toggles only available when you assign this options to a button like you have to do it for all the other features like HOLD or the TURBO modes at the moment ?
What is the cycle order, where do you want to have them added ..at the moment it is like you have requested:
double-tapped to cycle through the modes: Normal -> Turbo -> Toggle Turbo -> Hold -> Alternate Turbo -> Alternate Toggle Turbo

Yeah, they're basically the same as the other modes in the sense that they have to be assigned to a button before they can be used.

Preferably, the order would go Normal -> Turbo -> Toggle Turbo -> Multi-Function Toggle Turbo -> Hold -> Alternate Turbo -> Alternate Toggle Turbo -> Multi-Function Alternate Toggle Turbo.

Thanks for agreeing to try and add in a way to see what features are set and being used or not on buttons when in the config mode.


Oh, and a way to quickly reset BtnsFeature and BtnsToggle across all buttons, as well as QSBtns would also be very much appreciated, as it would replace this:
Code: Select all
void fDefault_Features() {
    F1 = 0;
    F2 = 0;
    F3 = 0;
    F4 = 0;
    F5 = 0;
    F6 = 0;
    F7 = 0;
    F8 = 0;
    F9 = 0;
    F10 = 0;
    F11 = 0;
    F12 = 0;
    F13 = 0;
    F14 = 0;
    QS = 0;
}
This should already be working the same way as your script does it. I only missed to put it in the description at the top of the script.

Ah, my bad.

I must have missed it when I was looking through the code you provided.

Thanks for letting me know.


Also, I just tested the new script you provided, and there's a single issue that I noticed.
Basically, you can triple tap a button when setting a feature, and it'll increment twice instead of just once.

Like, if I tap R2 three times in quick succession, it'll go from normal to turbo on the second tap, and then to Toggle Turbo on the third tap.

The script seems bug free other than that one issue.
User avatar
Fenria
Command Sergeant Major
Command Sergeant Major
 
Posts: 147
Joined: Thu May 21, 2015 5:56 pm

Re: Need help optimizing a script

Postby Scachi » Sat Feb 09, 2019 7:37 pm

Do you want the multi modes to be assigned with one of the two modes (turbo tap or hold tap) by default or do you have to select one first ?

Do you want to be able to "clear" the multi state somehow ? This may be only useful if you don't want to have one multi mode be active by default.

Sorry for all the questions.. I have a hard time reading this info from your code. All that numbers are driving me crazy :ashamed:
User avatar
Scachi
Brigadier General
Brigadier General
 
Posts: 3044
Joined: Wed May 11, 2016 6:25 am
Location: Germany

Re: Need help optimizing a script

Postby Fenria » Sat Feb 09, 2019 9:19 pm

I have no issues answering questions, so no need to be sorry.

Basically, the way the multi-mode feature works is that once it is set to a button, if the button is pressed for less than 200 milliseconds, released, then pressed again within 200 milliseconds and held down for 250 milliseconds, either an auto-turbo or an auto-alternate turbo is triggered depending on which of the two multi-mode functions is assigned to the button, but if the button is just pressed and held down for 1 second without being tapped, then an auto-hold is triggered, regardless of which of the two multi-mode functions is assigned, and once an auto-turbo/auto-alternate turbo or an auto-hold is triggered, the button can be tapped to revert it back to the appropriate multi-mode feature's default state.

I hope that helps, and if you have any other questions, feel free to ask.

Edit:
I just noticed that I kinda forgot to replace all the instances of "PT" with 200 when providing you with the code, which probably didn't help you figure it out on your own.

My bad.
Last edited by Fenria on Sat Feb 09, 2019 10:28 pm, edited 2 times in total.
User avatar
Fenria
Command Sergeant Major
Command Sergeant Major
 
Posts: 147
Joined: Thu May 21, 2015 5:56 pm

Re: Need help optimizing a script

Postby Scachi » Sat Feb 09, 2019 9:50 pm

Fenria wrote:I have no issues answering questions, so no need to be sorry.

Basically, the way the multi-mode feature works is that once it is set to a button, if the button is pressed for less than 200 milliseconds, released, then pressed again within 200 milliseconds and held down for 250 milliseconds, either an auto-turbo or an auto-alternate turbo is triggered depending on which of the two multi-mode functions is assigned to the button, but if the button is just pressed and held down for 1 second without being tapped, then an auto-hold is triggered, regardless of which of the two multi-mode functions is assigned, and once an auto-turbo/auto-alternate turbo or an auto-hold is triggered, the button can be tapped to revert it back to the appropriate multi-mode feature's default state.

I hope that helps, and if you have any other questions, feel free to ask.

Edit:
I just noticed that I kinda forgot to replace all the instances of "PT" with 200 when providing you with the code, which probably didn't help you figure it out on your own.

My bad.


Thank you for the detailed description, I was thinking it should work like this instead:
if a multi toggle is assigned to the button ..
- "a long hold" should set "hold an next tap"
- "1xtap+1press&hold" should set it to turbo on the next short tap
like a fast switch option between turbo/hold without having to go to the config mode first..
we have some bytecode space left if you want this one too :innocent_smile_1:
User avatar
Scachi
Brigadier General
Brigadier General
 
Posts: 3044
Joined: Wed May 11, 2016 6:25 am
Location: Germany

Re: Need help optimizing a script

Postby Fenria » Sat Feb 09, 2019 10:26 pm

I'm glad I was able to help you understand how the multi-mode functions worked.

Regarding the version you proposed, feel free to add that in as well, cause it would be interesing to see how it feels to use that.

Maybe holding down the share button and pressing a button like the previous way to activate the turbo/alternate turbo modes can put a button in that state?

It would also allow for a way to decide if a button would use turbo or alternate turbo for the "tap then press and hold" feature.
User avatar
Fenria
Command Sergeant Major
Command Sergeant Major
 
Posts: 147
Joined: Thu May 21, 2015 5:56 pm

Re: Need help optimizing a script

Postby Scachi » Sun Feb 10, 2019 3:05 pm

Fenria wrote:I'm glad I was able to help you understand how the multi-mode functions worked.

Regarding the version you proposed, feel free to add that in as well, cause it would be interesing to see how it feels to use that.

Maybe holding down the share button and pressing a button like the previous way to activate the turbo/alternate turbo modes can put a button in that state?

It would also allow for a way to decide if a button would use turbo or alternate turbo for the "tap then press and hold" feature.

Holding a btn with turbo assigned + press Share will switch "turbo<->alt turbo"
Holding a btn with multi_func_toggle assigned + press Options will switch "default multi<->tap multi"

The debug show thing is the only thing still missing.
Not sure when you want to be able to see assigned features of the buttons via the device monitor.
During regular usage or in config mode only ?

Here is the code:
Code: Select all
#pragma METAINFO("Fenria Special", 0, 5, "")
 
//
//  CONFIG MODE: 3x fast press TouchClick to enter and leave config mode
//   +DPAD-UP: CFGBTN_SCOPE   : button specific Turbo&Alternate&Hold AND quickscope  selection
//       -Double-Tap a button : to cycle through the available button specific features
//       -PS                  : clear all button features settings assignments and flags
//       -TouchClick Hold > 500ms: cycling through quickscope settings
//   +DPAD-RIGHT: CFGTURBO    : Turbo Timing adjustment
//       -PS : Turbo Timing reset
//   +DPAD-DOWN: CFGSENS_PROT : Sensitivity adjustment and Output Protocol selection
//        -Share : Output Protocol selection
//        -PS    : Sensitivity reset
 
//  Regular Usage:
//   + when using multi_func_toggle modes:
//      - holding the button + press Options will switch  "multi mode<->wrong multi mode"
//        my proposed/misunderstood multi_function_toggle version has no mode active by default
//        you have to select one with tap+press&hold or hold>1000ms. After that use a short tap to toggle it on/off
//        hold the button and tap share again to get back to the correct multi_func_toggle
//   + when using turbo modes:
//      - Buttonhold + Tap Share toggles turbo<->alt turbo
 
#include "ColorLED.gph"
 
 
// ++ BUTTON SPECIFIC FEATURES
//
// feature/mode identifier, for each button
#define FNONE     0  // no special function
#define FTURBOHN  1  // on hold = normal turbo
#define FTURBOTN  2  // tap = toggle normal turbo
#define FMULTIDN  3  // MULTI direct norm: dbltap+hold = turbo & hold>1sec = hold
#define FHOLD     4  // tap = toggle button hold
#define FTURBOHA  5  // on hold = alt turbo
#define FTURBOTA  6  // tap = toggle alt turbo
#define FMULTIDA  7  // MULTI direct alt: dbltap+hold = turbo&& hold>1sec = hold
#define F_MODES   8  // number of modes available to cycle through with dbl tap
#define FMULTITN  9  // MULTI tap alt : dbltap+hold = turbo & hold>1sec = hold , Btn+Share to toggle
#define FMULTITA  10 // MULTI tap norm: dbltap+hold = turbo & hold>1sec = hold , Btn+Share to toggle
 
// array used to output the feature name on feature selection cycling
char *FNAMES[] = {
  "Btn_   Mode 00: NONE",
  "Btn_   Mode 01: TURBO NORMAL HOLD",
  "Btn_   Mode 02: TURBO NORMAL TAP",
  "Btn_   Mode 03: MULTI NORMAL TURBO & HOLD",
  "Btn_   Mode 04: SIMPLE HOLD TAP",
  "Btn_   Mode 05: TURBO ALT HOLD",
  "Btn_   Mode 06: TURBO ALT TAP",
  "Btn_   Mode 07: MULTI ALT TURBO & HOLD",
  "Btn_   Mode 08: NOT USED",
  "Btn_   Mode 09: MULTI TAP NORMAL TURBO & HOLD",
  "Btn_   Mode 10: MULTI TAP ALT TURBO & HOLD",
};
 
// LED blink colors for feature toggles
uint8 LEDF[] = {
  CP,  // pink   on FNONE / Non special mode
  CB,  // blue   on FTURBOHN (hold,normal)     
  CA,  // amber  on FTURBOTN (toggle,normal)   
  CC,  // cyan   on FMULTIDN & FMULTITN
  CG,  // green  on FHOLD                     
  CR,  // red    on FTURBOHA (hold,alternate) 
  CW,  // white  on FTURBOTA (toggle,alternate)
  CC,  // cyan   on FMULTIDA & FMULTITA
};
 
// ++ LED Feedback state tracking flags in RGB order , position in array
#define idx_LEDFTA  0  // FTURBOA (alternate) +blink on active
#define idx_LEDFH   1  // FHOLD               +static on active
#define idx_LEDFTN  2  // FTURBON (normal)    +blink on active
bool bLED[] = { FALSE,FALSE,FALSE, };
 
 
// toggle state ids
#define TOFF      0   // toggled off
#define TON       1   // toggled on
#define TMTURBO   2   // multi turbo
#define TMHOLD    4   // multi hold
#define T_MODES   2   // for state checking using % modulo
 
// array used to output the toggle state name on change
char *TNAMES[] = {
  "Btn_   State 00: TOFF",
  "Btn_   State 01: TON",
  "Btn_   State 02: TMTURBO",
  "Btn_   State 03: TMTURBO+TON", // multi toggle
  "Btn_   State 04: TMHOLD",      // multi toggle
  "Btn_   State 05: TMHOLD+TON",  // multi toggle
};
 
 
uint8 BtnsFeature[21];// buttons feature flags (FNONE, FTURBOHN, ...)
uint8 BtnsToggle[21]; // buttons feature toggle state (TOFF,TON,...)
uint8 BtnTurboVal[2]; // buttons value to set for 0:turbo, 1:alt turbo, set by function fTurboTimer
#define TurboIdxN 0   // normal turbo is at this index in BtnTurboVal
#define TurboIdxA 1   // alternate turbo is at this index in BtnTurboVal
 
int16 TPress  =60// turbo button press time
int16 TRelease=60// turbo button release time
 
 
// ++ GENERAL FEATURES - non button specific
//
// ######## Quick Scope
bool bQScope =0; // quick scope state flag
uint32 QSTimeLimit=100; // timelimit of press time for starting quickscope combo
              //  scope    , fire
uint8 QSBtns[8] ={BUTTON_8 ,BUTTON_5//  L2 & R2 default
                  BUTTON_6 ,BUTTON_5//  R3 & R2
                  BUTTON_17,BUTTON_5//  Square & R2
                  200      ,200     ,  //  dummy for off state
                  };
uint8 QSCfg =6; // quickscope button pair to use 0,2,4,6 (6==off)
 
 
// ######## Stick Sensitivity and Deadzone
fix32 DeadZone=10.0;
int16 RSensitivity=100; // right stick sensitivity
int16 LSensitivity=100; // left  stick sensitivity
 
 
// ######## Output Protocol
#define PIO_NONE    0
#define PIO_AUTO    0
#define PIO_PS4     4
#define PIO_PS3     1
#define PIO_XB1     5
#define PIO_XB360   2
#define PIO_WII     3
#define PIO_HID     6
#define PIO_SWITCH  7
 
 
// ++ Configuration Mode
bool bConfigure=FALSE;
uint8 CfgMode =0;
#define CFGNONE       0 // no config sub entry (1,2,3) selected
#define CFGBTN_SCOPE  1
#define CFGTURBO      2
#define CFGSENS_PROT  3
 
char *CNAMES[]={
  "CfgMode 0 : CFGNONE      = Main Cfg Menu",
  "CfgMode 1 : CFGBTN_SCOPE = Btn Features & Quickscope",
  "CfgMode 2 : CFGTURBO     = Turbo Timing",
  "CfgMode 3 : CFGSENS_PROT = Sensitivity & Output Protocol",
};
 
// led feedback for configuration menu position
#define LCFGENTER 0
#define LCFGLEAVE 0
uint8 LEDCFG[] = {
  CP, // pink , entering+leaving config mode
};
 
 
init {
  // for testing
  /*
  TPress  =200;  // turbo button press time
  TRelease=200;  // turbo button release time
 
 
  BtnsFeature[BUTTON_10]=FHOLD; // hold feature
 
  BtnsFeature[BUTTON_5]=FTURBOHN; // turbo feature normal
 
  BtnsFeature[BUTTON_8]=FTURBOHA; // turbo feature alternate
  */

 
  /*
  bConfigure=TRUE;
  CfgMode=CFGBTN_SCOPE;
  */

}
 
 
main {
  // reset led flags
  bLED[0]=FALSE; bLED[1]=FALSE; bLED[2]=FALSE;
 
  fConfigToggle();
 
  if (bConfigure) {
      fConfigure(); // handling configuration logic
      if (elapsed_time()) { // TESTING: lower cpu usage, remove this when output gets through
        fNullOutput();      // zero output via set_val
        fDebug();           // debug output via set_val
      }
  } else {
      fButtons();   // buttons specific feature toggle and usage: hold, turbo hold, turbo toggle
      if (elapsed_time()) { // TESTING: lower cpu usage, remove this when output gets through
        fButtonLED(); // usage led feedback
      }
  }
 
  // ## always active stuff
  if (elapsed_time()) { // TESTING: lower cpu usage, this one should be fine as it uses no event_ stuff
    fTurboTimer(); // turbo and alternate turbo time tracker, sets values of array BtnTurboVal
  }
  fQuickScope(); // quick scope
  fSticks(); // stick deadzone and sensitivity
}
 
 
// button feature activity LED feedback
void fButtonLED() {
  // bLED[0] is hold feature,             green = LED_3
  // bLED[1] is turbo(normal) feature,    blue  = LED_1
  // bLED[2] is turbo(alternate) feature, red   = LED_2
  static bool bIdle=FALSE;
  static uint8 LastState[3]={2, 2, 2};
  static uint8 LastVal[3]= {2, 2, 2};
 
  // state change test
  if (LastState[0]!=bLED[0] || LastState[1]!=bLED[1] || LastState[2]!=bLED[2]) {
    LastState[0]=bLED[0]; LastState[1]=bLED[1]; LastState[2]=bLED[2]; // reset
    //printf("State changed");
 
    if (!(bLED[0] + bLED[1] + bLED[2])) { // idle
      bIdle=TRUE;
      ColorLED(LEDF[FNONE]); // pink led
      //printf("LED State: normal == idle == pink"); 
    } else { // busy
      bIdle=FALSE;
      LastVal[0]=2; LastVal[1]=2; LastVal[2]=2// reset
      //printf("LED State: busy");
    }
  } // eo: state change test
 
  if (!bIdle) { // not idle...set color according to active features
 
    // bLED[0] is hold feature ,            green = LED_3
    if (LastVal[idx_LEDFH]!=bLED[idx_LEDFH]) {
      LastVal[idx_LEDFH]=bLED[idx_LEDFH];
      led_set(LED_4,0.0,0);
      led_set(LED_3,(fix32)bLED[idx_LEDFH]*100f,0);
      //printf("led3: %d",LastVal[idx_LEDFH]);
 
 
    }
 
    // bLED[1] is turbo(normal) feature,    blue  = LED_1
    if (LastVal[idx_LEDFTN]!=bLED[idx_LEDFTN]*BtnTurboVal[TurboIdxN]) {
      LastVal[idx_LEDFTN]=bLED[idx_LEDFTN]*BtnTurboVal[TurboIdxN];
      led_set(LED_4,0.0,0);
      led_set(LED_1,(fix32)LastVal[idx_LEDFTN],0);     
      //printf("led1: %d",LastVal[idx_LEDFTN]);
    }
 
    // bLED[2] is turbo(alternate) feature, red   = LED_2
    if (LastVal[idx_LEDFTA]!=bLED[idx_LEDFTA]*BtnTurboVal[TurboIdxA]) {
      LastVal[idx_LEDFTA]=bLED[idx_LEDFTA]*BtnTurboVal[TurboIdxA];
      led_set(LED_4,0.0,0);
      led_set(LED_2,(fix32)LastVal[idx_LEDFTA],0);
      //printf("led2: %d",LastVal[idx_LEDFTA]);
    }
 
    // feature are selected and active but only one turbo is used, set non-turbo time to pink
    if (LastState[idx_LEDFH]==0 && LastVal[idx_LEDFTN]==0 && LastVal[idx_LEDFTA]==0) {
      ColorLED(LEDF[FNONE]); // pink led
    }
  }
}
 
// toggle configuration mode
void fConfigToggle() {
  if (event_active(BUTTON_2) || event_release(BUTTON_2)) { // less cpu usage
    if (fTaps(BUTTON_2,3,250)) {
      bConfigure=!bConfigure;
      CfgMode=CFGNONE; // set active submenu to none
 
      // CfgMode toggle notification
      if (bConfigure) {
        ColorLED(LEDCFG[LCFGENTER],140,140,3,LEDF[FNONE]);
        printf("CfgMode 0 : Entered = Main Menu");
      } else {
        ColorLED(LEDCFG[LCFGLEAVE],140,140,3,LEDF[FNONE]);
        printf("CfgMode Exited");
      }
    } // eo: tripple click
  }
}
 
// doing the configuration
void fConfigure() {
    static bool TClicked=FALSE; // for trigger quickscope button layout cycle with longer button hold
 
    if (CfgMode==CFGNONE) { // no sub entry selected
      if (event_active(BUTTON_10)) {
        CfgMode=CFGBTN_SCOPE;
        printf(CNAMES[CfgMode]);
      }
      if (event_active(BUTTON_13)) {
        CfgMode=CFGTURBO;
        printf(CNAMES[CfgMode]);
      }
      if (event_active(BUTTON_11)) {
        CfgMode=CFGSENS_PROT;
        printf(CNAMES[CfgMode]);
        }
    } // eo: CfgMode==CFGNONE
 
    else { // ## in sub entry
      if (event_active(BUTTON_3)) {
        CfgMode=CFGNONE; // back to main entry
        printf(CNAMES[CfgMode]);
        ColorLED(LEDCFG[0],140,140,3,LEDF[FNONE]);
      }
 
      switch(CfgMode) { // sub entry specific
        case CFGBTN_SCOPE:  // button feature and quickscope selection
                if (event_active(BUTTON_1)) fDefaultFeatures(); // PS button
                else {
                  fButtons(TRUE); // TRUE for feature selection
 
                  if (event_release(BUTTON_2)) TClicked=FALSE;
                  if (check_active(BUTTON_2,500) && !TClicked) {
                    TClicked=TRUE;
                    QSCfg=(QSCfg+2)%8;
                    if (QSCfg>=6) bQScope=FALSE; else bQScope=TRUE;
                    printf("quicksope (1:on/0:off) %d ,Button layout idx: %d, scope: Btn_%d, fire: Btn_%d",bQScope,QSCfg,QSBtns[QSCfg]+1,QSBtns[QSCfg+1]+1);
                  }
                }
          break;
        case CFGTURBO:      // button turbo timing adjustment
                if (event_active(BUTTON_1)) fTurboDefault(); // PS button
                else fTurboAdjust();
          break;
        case CFGSENS_PROT:  // sensitivity and output protocol adjustment
                if (event_active(BUTTON_18)) fOutput(); // Share : change output protocol
                if (event_active(BUTTON_1)) fSensitivityDefault(); // PS button
                else fSensitivityAdjust();
          break;
      }
    }
}
 
 
// button loop for config and usage
void fButtons(bool cfg) {
  uint8 btn;
 
  for (btn=BUTTON_4;btn<=BUTTON_17;btn++) {  // buttons PS4: R1...Square
    // reduces cpu usage
    if ( !event_active(btn) && !event_release(btn) && !get_actual(btn) && !BtnsToggle[btn]==TON ) continue;
 
    if (cfg) fBtnSelect(btn); // select buttons feature                   
    else fBtnUsage(btn);      // use buttons feature
  }
}
 
// clear all button features assignments and quick scope
void fDefaultFeatures() {
  uint8 btn;
  for (btn=BUTTON_4;btn<=BUTTON_17;btn++) { // buttons PS4: R1..Square
    BtnsFeature[btn]=FNONE;
    BtnsToggle[btn]=TOFF;
  }
  QSCfg=6;
  bQScope=FALSE;
}
 
// select feature to use a button
void fBtnSelect(uint8 btn) {
    // cycle through modes with dbl tap
    if (fTaps(btn,2,250)) {
      BtnsFeature[btn]=(BtnsFeature[btn]+1)%F_MODES;
      BtnsToggle[btn]=TOFF; // toggle state reset
 
      if (BtnsFeature[btn] < F_MODES ) { // led toggle feedback
        PrintNAME(FNAMES[BtnsFeature[btn]],btn); // output button_name and its feature
        if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(BtnsFeature[btn],200,200,2,LEDF[FNONE]);
      }
    }
}
 
// use buttons selected features
void fBtnUsage(uint8 btn) {
  static uint8 block=FALSE;
 
  // Button feature ON/OFF toggle with short tap
  if (BtnsFeature[btn]!=FNONE && event_release(btn) && time_active(btn) <=250) {
    if (BtnsToggle[btn]%T_MODES==TOFF) {
      BtnsToggle[btn]+=TON; // sets 1,3,5 (3,5 for multi toggle)
      if (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA) BtnsToggle[btn]=TOFF;
      if ((BtnsFeature[btn]==FMULTITN || BtnsFeature[btn]==FMULTITA) && BtnsToggle[btn] < T_MODES) BtnsToggle[btn]=TOFF;
    } else if (BtnsToggle[btn]%T_MODES==TON) {                       // disable
      if (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA) BtnsToggle[btn]=TOFF;
      else BtnsToggle[btn]-=TON; // sets 0,2,4 (2,4 for multi org)
    }
  }
 
  // Buttonhold + poress Share toggles turbo<->alt turbo
  if (get_actual(btn)) {
    set_val(BUTTON_3,0);set_val(BUTTON_18,0); // block share & options
    if (event_active(BUTTON_18)) fTurboModeFlip(btn);
  }
 
  // multi mode selection : tap+presshold = turbo || hold>1sec = hold
  if ( (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA || BtnsFeature[btn]==FMULTITN || BtnsFeature[btn]==FMULTITA)
    && (event_release(btn) || event_active(btn) || get_actual(btn))
   ) {
    if (event_release(btn)) block=FALSE;
    if (fTaps(btn,2,200,250)) { // tap+presshold
      block=TRUE;
      if (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA) BtnsToggle[btn]=TMTURBO+TON; // direct activation
      else if (BtnsFeature[btn]==FMULTITN || BtnsFeature[btn]==FMULTITA) BtnsToggle[btn]=TMTURBO+TOFF;  // req additional tap
      PrintNAME(FNAMES[BtnsFeature[btn]],btn); // output button_name and its feature
      PrintNAME(TNAMES[BtnsToggle[btn]],btn); // output button_name and its toggle
    }
    if (!block && check_active(btn,1000)) { // hold
      block=TRUE;
      if (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA ) BtnsToggle[btn]=TMHOLD+TON; // direct activation
      else if (BtnsFeature[btn]==FMULTITN || BtnsFeature[btn]==FMULTITA) BtnsToggle[btn]=TMHOLD+TOFF; // req additional tap
      PrintNAME(FNAMES[BtnsFeature[btn]],btn); // output button_name and its feature
      PrintNAME(TNAMES[BtnsToggle[btn]],btn); // output button_name and its toggle
    }
    // switch multi normal<->toggle(missunderstood) , btn+opress ptions
    if (get_actual(btn) && event_active(BUTTON_3)){
      if      (BtnsFeature[btn]==FMULTIDN) { BtnsFeature[btn]=FMULTITN; BtnsToggle[btn]=TOFF;}
      else if (BtnsFeature[btn]==FMULTITN) { BtnsFeature[btn]=FMULTIDN; BtnsToggle[btn]=TOFF;}
      else if (BtnsFeature[btn]==FMULTIDA) { BtnsFeature[btn]=FMULTITA; BtnsToggle[btn]=TOFF; }
      else if (BtnsFeature[btn]==FMULTITA) { BtnsFeature[btn]=FMULTIDA; BtnsToggle[btn]=TOFF;}
      PrintNAME(FNAMES[BtnsFeature[btn]],btn); // output button_name and its feature
    }
  }
 
  // feature with toggle
  if (BtnsToggle[btn]%T_MODES==TON) {
    if (BtnsFeature[btn]==FHOLD || BtnsToggle[btn]==TMHOLD+TON) { bLED[idx_LEDFH] =1; set_val(btn,100); }
    else if (BtnsFeature[btn]==FTURBOTN || BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTITN) {
      bLED[idx_LEDFTN]=1; set_val(btn,BtnTurboVal[TurboIdxN]);
    }
    else if (BtnsFeature[btn]==FTURBOTA || BtnsFeature[btn]==FMULTIDA || BtnsFeature[btn]==FMULTITA) {
      bLED[idx_LEDFTA]=1; set_val(btn,BtnTurboVal[TurboIdxA]);
    }
  }
 
  // active when the button is held down
  if (BtnsFeature[btn]==FTURBOHN && get_actual(btn)) { bLED[idx_LEDFTN]=1; set_val(btn,BtnTurboVal[TurboIdxN]); }
  if (BtnsFeature[btn]==FTURBOHA && get_actual(btn)) { bLED[idx_LEDFTA]=1; set_val(btn,BtnTurboVal[TurboIdxA]); }
}
 
// turbo<->altturbo
void fTurboModeFlip(uint8 btn) {
  if      (BtnsFeature[btn]==FTURBOHN) BtnsFeature[btn]=FTURBOHA; // hold
  else if (BtnsFeature[btn]==FTURBOHA) BtnsFeature[btn]=FTURBOHN;
  else if (BtnsFeature[btn]==FTURBOTN) BtnsFeature[btn]=FTURBOTA; // toggle
  else if (BtnsFeature[btn]==FTURBOTA) BtnsFeature[btn]=FTURBOTN;
  else if (BtnsFeature[btn]==FMULTIDN) BtnsFeature[btn]=FMULTIDA; // multi direct
  else if (BtnsFeature[btn]==FMULTIDA) BtnsFeature[btn]=FMULTIDN;
  else if (BtnsFeature[btn]==FMULTITN) BtnsFeature[btn]=FMULTITA; // multi toggle
  else if (BtnsFeature[btn]==FMULTITN) BtnsFeature[btn]=FMULTITA;
  PrintNAME(FNAMES[BtnsFeature[btn]],btn); // output button_name and its feature
}
 
 
// add the button id into the string for output
void PrintNAME(char *name, uint8 btn) {
  (name+4)=(btn+1)/10+48; // 0,1,2,3 tens
  (name+5)=(btn+1)%10+48; // 0..9    ones
  printf(name);
}
 
 
// adjust turbo press and release times
void fTurboAdjust() {
  // R1: TPress+10
  if (event_active(BUTTON_4) && TPress < 2000) { TPress += 10; }
  // L1: TPress-10
  if (event_active(BUTTON_7) && TPress > 20  ) { TPress -= 10; }
 
  // R2: TRelease+10
  if (event_active(BUTTON_5) && TRelease < 2000) { TRelease += 10; }
  // L2: TRelease-10
  if (event_active(BUTTON_8) && TRelease > 20  ) { TRelease -= 10;}
}
 
// reset turbo timings
void fTurboDefault() {
    TPress = 40;
    TRelease = 40;
    //fReset();
}
 
// sets current button value for the turbo modes to use when active
void fTurboTimer() {
  uint32 syst = system_time()
  static  uint32 TurboTimer=system_time();
  static  uint32 AltTurboTimer=0;
 
  if ( syst > TurboTimer && TurboTimer != 0 ) { // TURBO
    if (AltTurboTimer == 0 ) AltTurboTimer=TurboTimer + TPress + TRelease/2 - TPress/2;
    if ( syst > TurboTimer && syst <=TurboTimer+TPress ) BtnTurboVal[TurboIdxN]=100;
    else if ( syst > TurboTimer+TPress && syst < TurboTimer+TPress+TRelease) BtnTurboVal[TurboIdxN]=0;
    else if ( syst >= TurboTimer+TPress+TRelease) TurboTimer = syst;
  }
  if ( syst > AltTurboTimer && AltTurboTimer != 0 ) { // TURBO ALTERNATE
    if ( syst > AltTurboTimer && syst <=AltTurboTimer+TPress ) BtnTurboVal[TurboIdxA]=100;
    else if ( syst > AltTurboTimer+TPress && syst < AltTurboTimer+TPress+TRelease) BtnTurboVal[TurboIdxA]=0;
    else if ( syst >= AltTurboTimer+TPress+TRelease) AltTurboTimer = 0;
  }
}
 
 
void fQuickScope() {
  if (bQScope && time_active(QSBtns[QSCfg]) < QSTimeLimit && event_release(QSBtns[QSCfg]))    {
      combo_run(cQuickScope);
  }
}
 
combo cQuickScope {
    set_val(QSBtns[QSCfg], 100);
    wait(500);
    set_val(QSBtns[QSCfg], 100);
    set_val(QSBtns[QSCfg+1], 100);
    wait(50);
    set_val(QSBtns[QSCfg], 0);
    set_val(QSBtns[QSCfg+1], 0);
}
 
 
void fSensitivityAdjust() {
  // R1: TPress+10
  if (event_active(BUTTON_4) && RSensitivity < 200) { RSensitivity += 10; }
  // L1: TPress-10
  if (event_active(BUTTON_7) && LSensitivity < 200) { LSensitivity += 10; }
  // R2: TRelease+10
  if (event_active(BUTTON_5) && RSensitivity > 20)  { RSensitivity -= 10; }
  // L2: TRelease-10
  if (event_active(BUTTON_8) && LSensitivity > 20)  { LSensitivity -= 10; }
}
 
void fSensitivityDefault() {
    RSensitivity = 100;
    LSensitivity = 100;
}
 
// deadzone and sensitivity
void fSticks() {
  fDZSens(STICK_1_X,DeadZone,RSensitivity);
  fDZSens(STICK_1_Y,DeadZone,RSensitivity);
  fDZSens(STICK_2_X,DeadZone,LSensitivity);
  fDZSens(STICK_2_Y,DeadZone,LSensitivity);
 
}
 
void fDZSens(uint8 axis, fix32 dz,int16 sens) {
  if (abs(get_val(axis)) <= dz) {
      set_val(axis, 0.0);
  } else fSensitivity(axis, 50, sens);
}
 
void fSensitivity(uint8 id, int16 mid, int16 sen) {
    int16 val = (int16)get_val(id);
    if(mid != 0)    {
        int16 val_s = (val >= 0) ? 1 : -1;
        val *= val_s;
        if(val <= mid)    {
            val = (val * 50) / mid;
        }
        else {
            val = ((50 * (val - mid)) / (100 - mid)) + 50;
        }
        val *= val_s;
    }
    if(sen != 0)    {
        val = (val * sen) / 100;
    }
    set_val(id, clamp(val, -100, 100));
    return;
}
 
// cycle through output protocols
void fOutput() {
    static uint8 IOP=4;
    IOP=(IOP+1)%4;
 
    if (IOP == 0)    {
        fOutputProtocol(PIO_XB360);
    }
    if (IOP == 1)    {
        fOutputProtocol(PIO_PS3);
    }
    if (IOP == 2)    {
        fOutputProtocol(PIO_XB1);
    }
    if (IOP == 3)    {
        fOutputProtocol(PIO_PS4);
    }
}
 
// activate output protocol
void fOutputProtocol(uint8 id) {
    port_disconnect();
    switch(id)    {
        case PIO_PS3:
            port_connect(PORT_USB_C, PROTOCOL_PS3);
            printf("PROTOCOL_PS3");
            break;
        case PIO_XB360:
            port_connect(PORT_USB_C, PROTOCOL_XB360);
            printf("PROTOCOL_XB360");
            break;
        case PIO_PS4:
            port_connect(PORT_USB_C, PROTOCOL_PS4);
            printf("PROTOCOL_PS4");
            break;
        case PIO_XB1:
            port_connect(PORT_USB_C, PROTOCOL_XB1);
            printf("PROTOCOL_XB1");
            break;
        case PIO_SWITCH:
            port_connect(PORT_USB_C, PROTOCOL_SWITCH);
            printf("PROTOCOL_SWITCH");
            break;
    }
    return;
}
 
// check button tapped "taps" times, each press in the timelimit, with optional hold time check
uint8 fTaps(uint8 btn, uint8 taps, uint32 tlimit, uint32 thold) {
  static uint8 lastbtn=200, itaps=0;
  static uint32 lastta=0;
 
  if (event_active(btn)) {
    if (btn!=lastbtn || lastta+time_release(btn)>tlimit) { lastbtn=btn; itaps=1; }
    else if (btn==lastbtn) itaps++;   
    if (itaps==taps && !thold) { itaps=0; return TRUE; }
  }
  if (thold && check_active(btn,thold) && itaps==taps) {
    itaps=0;
    return TRUE;
  }
  if (event_release(btn) && btn==lastbtn) lastta=time_active(btn);
  return FALSE;
}
 
 
// block output
void fNullOutput() {
  set_val(BUTTON_1,0); set_val(BUTTON_2,0); set_val(BUTTON_3,0); set_val(BUTTON_4,0);
  set_val(BUTTON_5,0); set_val(BUTTON_6,0); set_val(BUTTON_7,0); set_val(BUTTON_8,0);
  set_val(BUTTON_9,0); set_val(BUTTON_10,0); set_val(BUTTON_11,0); set_val(BUTTON_12,0);
  set_val(BUTTON_13,0); set_val(BUTTON_14,0); set_val(BUTTON_15,0); set_val(BUTTON_16,0);
  set_val(BUTTON_17,0); set_val(BUTTON_18,0); set_val(BUTTON_19,0); set_val(BUTTON_20,0);
  set_val(BUTTON_21,0);
  set_val(STICK_1_X,0); set_val(STICK_1_Y,0); set_val(STICK_2_X,0); set_val(STICK_2_Y,0);
  set_val(POINT_1_X,0); set_val(POINT_1_Y,0); set_val(POINT_2_X,0); set_val(POINT_2_Y,0);
  set_val(ACCEL_1_X,0); set_val(ACCEL_1_Y,0); set_val(ACCEL_1_Z,0);
  set_val(ACCEL_2_X,0); set_val(ACCEL_2_Y,0); set_val(ACCEL_2_Z,0);
  set_val(GYRO_1_X,0); set_val(GYRO_1_Y,0); set_val(GYRO_1_Z,0);
}
 
void fDebug() {
  set_val(ACCEL_1_Z, TPress / 10);
  set_val(ACCEL_2_X, TRelease / 10);
  set_val(ACCEL_2_Z, CfgMode);
}
 
User avatar
Scachi
Brigadier General
Brigadier General
 
Posts: 3044
Joined: Wed May 11, 2016 6:25 am
Location: Germany

Re: Need help optimizing a script

Postby Fenria » Sun Feb 10, 2019 3:49 pm

I'll have to test the script when I get a chance tomorrow, cause I'm a bit busy today.

Regarding when I would like to see the assigned features of the buttons, just in config mode would be preferred.

I was thinking make it part of "fDebug".

Thank you for all your help so far.
I really appreciate it.
User avatar
Fenria
Command Sergeant Major
Command Sergeant Major
 
Posts: 147
Joined: Thu May 21, 2015 5:56 pm

Re: Need help optimizing a script

Postby Scachi » Sun Feb 10, 2019 11:24 pm

Button Info added to BUTTON_21 in the Device Monitor and text output at the Output Panel.

Code: Select all
#pragma METAINFO("Fenria Special", 0, 6, "")
 
#define DebugTxtOutputPanel // comment it to disable Debug Output Panel text
 
//  CONFIG MODE: 3x fast press TouchClick to enter and leave config mode
//   +DPAD-UP: CFGBTN_SCOPE   : button specific Turbo&Alternate&Hold AND quickscope  selection
//       -Double-Tap a button : to cycle through the available button specific features
//       -PS                  : clear all button features settings assignments and flags
//       -TouchClick Hold > 500ms: cycling through quickscope settings
//     +DEBUG : button information is written to BUTTON_21 on CFGBTN_SCOPE mode only
//       -Dev-Mon Button_21, Format: BtnNr NN*1000 , Feature FF , Toggle TT/100
//
//   +DPAD-RIGHT: CFGTURBO    : Turbo Timing adjustment
//       -PS : Turbo Timing reset
//
//   +DPAD-DOWN: CFGSENS_PROT : Sensitivity adjustment and Output Protocol selection
//        -Share : Output Protocol selection
//        -PS    : Sensitivity reset
 
//  Regular Usage:
//   + when using multi_func_toggle modes:
//      - holding the button + press Options will switch  "multi mode<->wrong multi mode"
//        my proposed/misunderstood multi_function_toggle version has no mode active by default
//        you have to select one with tap+press&hold or hold>1000ms. After that use a short tap to toggle it on/off
//        hold the button and tap share again to get back to the correct multi_func_toggle
//   + when using turbo modes:
//      - Buttonhold + Tap Share toggles turbo<->alt turbo
 
#include "ColorLED.gph"
 
// ++ BUTTON SPECIFIC FEATURES
//
// feature/mode identifier, for each button
#define FNONE     0  // no special function
#define FTURBOHN  1  // on hold = normal turbo
#define FTURBOTN  2  // tap = toggle normal turbo
#define FMULTIDN  3  // MULTI direct norm: dbltap+hold = turbo & hold>1sec = hold
#define FHOLD     4  // tap = toggle button hold
#define FTURBOHA  5  // on hold = alt turbo
#define FTURBOTA  6  // tap = toggle alt turbo
#define FMULTIDA  7  // MULTI direct alt: dbltap+hold = turbo&& hold>1sec = hold
#define F_MODES   8  // number of modes available to cycle through with dbl tap
#define FMULTITN  9  // MULTI tap alt : dbltap+hold = turbo & hold>1sec = hold , Btn+Share to toggle
#define FMULTITA  10 // MULTI tap norm: dbltap+hold = turbo & hold>1sec = hold , Btn+Share to toggle
 
// array used to output the feature name on feature selection cycling
char *FNAMES[] = {
  "Feature 00: NONE",
  "Feature 01: TURBO NORMAL HOLD",
  "Feature 02: TURBO NORMAL TAP",
  "Feature 03: MULTI NORMAL TURBO & HOLD",
  "Feature 04: SIMPLE HOLD TAP",
  "Feature 05: TURBO ALT HOLD",
  "Feature 06: TURBO ALT TAP",
  "Feature 07: MULTI ALT TURBO & HOLD",
  "Feature 08: NOT USED",
  "Feature 09: MULTI TAP NORMAL TURBO & HOLD",
  "Feature 10: MULTI TAP ALT TURBO & HOLD",
};
 
// LED blink colors for feature toggles
uint8 LEDF[] = {
  CP,  // pink   on FNONE / Non special mode
  CB,  // blue   on FTURBOHN (hold,normal)     
  CA,  // amber  on FTURBOTN (toggle,normal)   
  CC,  // cyan   on FMULTIDN & FMULTITN
  CG,  // green  on FHOLD                     
  CR,  // red    on FTURBOHA (hold,alternate) 
  CW,  // white  on FTURBOTA (toggle,alternate)
  CC,  // cyan   on FMULTIDA & FMULTITA
};
 
// ++ LED Feedback state tracking flags in RGB order , position in array
#define idx_LEDFTA  0  // FTURBOA (alternate) +blink on active
#define idx_LEDFH   1  // FHOLD               +static on active
#define idx_LEDFTN  2  // FTURBON (normal)    +blink on active
bool bLED[] = { FALSE,FALSE,FALSE, };
 
 
// toggle state ids
#define TOFF      0   // toggled off
#define TON       1   // toggled on
#define TMTURBO   2   // multi turbo
#define TMHOLD    4   // multi hold
#define T_MODES   2   // for state checking using % modulo
 
// array used to output the toggle state name on change
char *TNAMES[] = {
  "State 00: TOFF",
  "State 01: TON",
  "State 02: TMTURBO",
  "State 03: TMTURBO+TON", // multi toggle
  "State 04: TMHOLD",      // multi toggle
  "State 05: TMHOLD+TON",  // multi toggle
};
 
 
uint8 BtnsFeature[21];// buttons feature flags (FNONE, FTURBOHN, ...)
uint8 BtnsToggle[21]; // buttons feature toggle state (TOFF,TON,...)
uint8 BtnTurboVal[2]; // buttons value to set for 0:turbo, 1:alt turbo, set by function fTurboTimer
#define TurboIdxN 0   // normal turbo is at this index in BtnTurboVal
#define TurboIdxA 1   // alternate turbo is at this index in BtnTurboVal
 
int16 TPress  =60// turbo button press time
int16 TRelease=60// turbo button release time
 
 
// ++ GENERAL FEATURES - non button specific
//
// ######## Quick Scope
bool bQScope =0; // quick scope state flag
uint32 QSTimeLimit=100; // timelimit of press time for starting quickscope combo
              //  scope    , fire
uint8 QSBtns[8] ={BUTTON_8 ,BUTTON_5//  L2 & R2 default
                  BUTTON_6 ,BUTTON_5//  R3 & R2
                  BUTTON_17,BUTTON_5//  Square & R2
                  200      ,200     ,  //  dummy for off state
                  };
uint8 QSCfg =6; // quickscope button pair to use 0,2,4,6 (6==off)
 
 
// ######## Stick Sensitivity and Deadzone
fix32 DeadZone=10.0;
int16 RSensitivity=100; // right stick sensitivity
int16 LSensitivity=100; // left  stick sensitivity
 
 
// ######## Output Protocol
#define PIO_NONE    0
#define PIO_AUTO    0
#define PIO_PS4     4
#define PIO_PS3     1
#define PIO_XB1     5
#define PIO_XB360   2
#define PIO_WII     3
#define PIO_HID     6
#define PIO_SWITCH  7
 
 
// ++ Configuration Mode
bool bConfigure=FALSE;
uint8 CfgMode =0;
#define CFGNONE       0 // no config sub entry (1,2,3) selected
#define CFGBTN_SCOPE  1
#define CFGTURBO      2
#define CFGSENS_PROT  3
 
char *CNAMES[]={
  "CfgMode 0: CFGNONE      = Main Cfg Menu",
  "CfgMode 1: CFGBTN_SCOPE = Btn Features & Quickscope",
  "CfgMode 2: CFGTURBO     = Turbo Timing",
  "CfgMode 3: CFGSENS_PROT = Sensitivity & Output Protocol",
};
 
// led feedback for configuration menu position
#define LCFGENTER 0
#define LCFGLEAVE 0
uint8 LEDCFG[] = {
  CP, // pink , entering+leaving config mode
};
 
init {
  // for testing
  /*
  TPress  =200;  // turbo button press time
  TRelease=200;  // turbo button release time
  BtnsFeature[BUTTON_10]=FHOLD; // hold feature
  BtnsFeature[BUTTON_5]=FTURBOHN; // turbo feature normal
  BtnsFeature[BUTTON_8]=FTURBOHA; // turbo feature alternate
  */

  /*
  bConfigure=TRUE;
  CfgMode=CFGBTN_SCOPE;
  */

}
 
 
main {
  // reset led flags
  bLED[0]=FALSE; bLED[1]=FALSE; bLED[2]=FALSE;
 
  fConfigToggle();
 
  if (bConfigure) {
      fConfigure(); // handling configuration logic
      if (elapsed_time()) { // TESTING: lower cpu usage, remove this when output gets through
        fNullOutput();      // zero output via set_val
        fDebug();           // debug output via set_val
      }
  } else {
      fButtons();   // buttons specific feature toggle and usage: hold, turbo hold, turbo toggle
      if (elapsed_time()) { // TESTING: lower cpu usage, remove this when output gets through
        fButtonLED(); // usage led feedback
      }
  }
 
  // ## always active stuff
  if (elapsed_time()) { // TESTING: lower cpu usage, this one should be fine as it uses no event_ stuff
    fTurboTimer(); // turbo and alternate turbo time tracker, sets values of array BtnTurboVal
  }
  fQuickScope(); // quick scope
  fSticks(); // stick deadzone and sensitivity
}
 
 
// button feature activity LED feedback
void fButtonLED() {
  // bLED[0] is hold feature,             green = LED_3
  // bLED[1] is turbo(normal) feature,    blue  = LED_1
  // bLED[2] is turbo(alternate) feature, red   = LED_2
  static bool bIdle=FALSE;
  static uint8 LastState[3]={2, 2, 2};
  static uint8 LastVal[3]= {2, 2, 2};
 
  // state change test
  if (LastState[0]!=bLED[0] || LastState[1]!=bLED[1] || LastState[2]!=bLED[2]) {
    LastState[0]=bLED[0]; LastState[1]=bLED[1]; LastState[2]=bLED[2]; // reset
    //printf("State changed");
 
    if (!(bLED[0] + bLED[1] + bLED[2])) { // idle
      bIdle=TRUE;
      ColorLED(LEDF[FNONE]); // pink led
      //printf("LED State: normal == idle == pink"); 
    } else { // busy
      bIdle=FALSE;
      LastVal[0]=2; LastVal[1]=2; LastVal[2]=2// reset
      //printf("LED State: busy");
    }
  } // eo: state change test
 
  if (!bIdle) { // not idle...set color according to active features
 
    // bLED[0] is hold feature ,            green = LED_3
    if (LastVal[idx_LEDFH]!=bLED[idx_LEDFH]) {
      LastVal[idx_LEDFH]=bLED[idx_LEDFH];
      led_set(LED_4,0.0,0);
      led_set(LED_3,(fix32)bLED[idx_LEDFH]*100f,0);
      //printf("led3: %d",LastVal[idx_LEDFH]);
 
 
    }
 
    // bLED[1] is turbo(normal) feature,    blue  = LED_1
    if (LastVal[idx_LEDFTN]!=bLED[idx_LEDFTN]*BtnTurboVal[TurboIdxN]) {
      LastVal[idx_LEDFTN]=bLED[idx_LEDFTN]*BtnTurboVal[TurboIdxN];
      led_set(LED_4,0.0,0);
      led_set(LED_1,(fix32)LastVal[idx_LEDFTN],0);     
      //printf("led1: %d",LastVal[idx_LEDFTN]);
    }
 
    // bLED[2] is turbo(alternate) feature, red   = LED_2
    if (LastVal[idx_LEDFTA]!=bLED[idx_LEDFTA]*BtnTurboVal[TurboIdxA]) {
      LastVal[idx_LEDFTA]=bLED[idx_LEDFTA]*BtnTurboVal[TurboIdxA];
      led_set(LED_4,0.0,0);
      led_set(LED_2,(fix32)LastVal[idx_LEDFTA],0);
      //printf("led2: %d",LastVal[idx_LEDFTA]);
    }
 
    // feature are selected and active but only one turbo is used, set non-turbo time to pink
    if (LastState[idx_LEDFH]==0 && LastVal[idx_LEDFTN]==0 && LastVal[idx_LEDFTA]==0) {
      ColorLED(LEDF[FNONE]); // pink led
    }
  }
}
 
// toggle configuration mode
void fConfigToggle() {
  if (event_active(BUTTON_2) || event_release(BUTTON_2)) { // less cpu usage
    if (fTaps(BUTTON_2,3,250)) {
      bConfigure=!bConfigure;
      CfgMode=CFGNONE; // set active submenu to none
 
      // CfgMode toggle notification
      if (bConfigure) {
        ColorLED(LEDCFG[LCFGENTER],140,140,3,LEDF[FNONE]);
        printDebug(TRUE,"CfgMode 0 : Entered = Main Menu",TRUE);
      } else {
        ColorLED(LEDCFG[LCFGLEAVE],140,140,3,LEDF[FNONE]);
        printDebug(TRUE,"CfgMode Exited",TRUE);
      }
    } // eo: tripple click
  }
}
 
// doing the configuration
void fConfigure() {
    static bool TClicked=FALSE; // for trigger quickscope button layout cycle with longer button hold
 
    if (CfgMode==CFGNONE) { // no sub entry selected
      if (event_active(BUTTON_10)) {
        CfgMode=CFGBTN_SCOPE;
        printDebug(TRUE,CNAMES[CfgMode],TRUE);
      }
      if (event_active(BUTTON_13)) {
        CfgMode=CFGTURBO;
        printDebug(TRUE,CNAMES[CfgMode],TRUE);
      }
      if (event_active(BUTTON_11)) {
        CfgMode=CFGSENS_PROT;
        printDebug(TRUE,CNAMES[CfgMode],TRUE);
        }
    } // eo: CfgMode==CFGNONE
 
    else { // ## in sub entry
      if (event_active(BUTTON_3)) {
        CfgMode=CFGNONE; // back to main entry
        printDebug(TRUE,CNAMES[CfgMode],TRUE);
        ColorLED(LEDCFG[0],140,140,3,LEDF[FNONE]);
      }
 
      switch(CfgMode) { // sub entry specific
        case CFGBTN_SCOPE:  // button feature and quickscope selection
                if (event_active(BUTTON_1)) fDefaultFeatures(); // PS button
                else {
                  fButtons(TRUE); // TRUE for feature selection
                  if (event_release(BUTTON_2)) TClicked=FALSE;
                  if (check_active(BUTTON_2,500) && !TClicked) {
                    TClicked=TRUE;
                    QSCfg=(QSCfg+2)%8;
                    if (QSCfg>=6) bQScope=FALSE; else bQScope=TRUE;
                    //printf("quickscope (1:on/0:off) %d ,Button layout idx: %d, scope: Btn_%d, fire: Btn_%d",bQScope,QSCfg,QSBtns[QSCfg]+1,QSBtns[QSCfg+1]+1);
                    printDebug(TRUE,"Quickscope , enabled=");
                    if (bQScope) print("TRUE"); else print("FALSE");
                    print(" , Scope Btn_",FALSE,QSBtns[QSCfg]+1); print(" , Fire Btn_",FALSE,QSBtns[QSCfg+1]+1);
                    print(NULL);
                  }
                }
          break;
        case CFGTURBO:      // button turbo timing adjustment
                if (event_active(BUTTON_1)) fTurboDefault(); // PS button
                else fTurboAdjust();
          break;
        case CFGSENS_PROT:  // sensitivity and output protocol adjustment
                if (event_active(BUTTON_18)) fOutput(); // Share : change output protocol
                if (event_active(BUTTON_1)) fSensitivityDefault(); // PS button
                else fSensitivityAdjust();
          break;
      }
    }
}
 
 
// button loop for config and usage
void fButtons(bool cfg) {
  uint8 btn;
 
  for (btn=BUTTON_4;btn<=BUTTON_17;btn++) {  // buttons PS4: R1...Square
    // reduces cpu usage
    if ( !event_active(btn) && !event_release(btn) && !get_actual(btn) && !BtnsToggle[btn]==TON ) continue;
 
    if (cfg) fBtnSelect(btn); // select buttons feature                   
    else fBtnUsage(btn);      // use buttons feature
  }
}
 
// clear all button features assignments and quick scope
void fDefaultFeatures() {
  uint8 btn;
  for (btn=BUTTON_4;btn<=BUTTON_17;btn++) { // buttons PS4: R1..Square
    BtnsFeature[btn]=FNONE;
    BtnsToggle[btn]=TOFF;
  }
  QSCfg=6;
  bQScope=FALSE;
}
 
// select feature for the button
void fBtnSelect(uint8 btn) {
    // cycle through modes with dbl tap 
    if (fTaps(btn,2,250)) {
      BtnsFeature[btn]=(BtnsFeature[btn]+1)%F_MODES;
      BtnsToggle[btn]=TOFF; // toggle state reset
 
      if (BtnsFeature[btn] < F_MODES ) { // led toggle feedback
        fDebugBtn(btn);
        if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(BtnsFeature[btn],200,200,2,LEDF[FNONE]);
      }
    }
 
    // update debug info for current button
    if (event_active(btn)) fDebugBtn(btn);
}
 
// use buttons selected features
void fBtnUsage(uint8 btn) {
 
  // Button feature ON/OFF toggle with short tap
  if (BtnsFeature[btn]!=FNONE && event_release(btn) && time_active(btn) <=250) {
    if (BtnsToggle[btn]%T_MODES==TOFF) {
      BtnsToggle[btn]+=TON; // sets 1,3,5 (3,5 for multi toggle)
      if (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA) BtnsToggle[btn]=TOFF;
      if ((BtnsFeature[btn]==FMULTITN || BtnsFeature[btn]==FMULTITA) && BtnsToggle[btn] < T_MODES) BtnsToggle[btn]=TOFF;
    } else if (BtnsToggle[btn]%T_MODES==TON) {                       // disable
      if (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA) BtnsToggle[btn]=TOFF;
      else BtnsToggle[btn]-=TON; // sets 0,2,4 (2,4 for multi org)
    }
  }
 
  // Buttonhold + press Share toggles turbo<->alt turbo
  if (get_actual(btn)) {
    set_val(BUTTON_3,0);set_val(BUTTON_18,0); // block share & options
    if (event_active(BUTTON_18)) fTurboModeFlip(btn);
  }
 
  // multi feature mode : tap+presshold = turbo || hold>1sec = hold
  if (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA || BtnsFeature[btn]==FMULTITN || BtnsFeature[btn]==FMULTITA) {
    if (event_release(btn) || event_active(btn) || get_actual(btn)) fMultiFeature(btn);
  }
 
  // feature with toggle
  if (BtnsToggle[btn]%T_MODES==TON) {
    if (BtnsFeature[btn]==FHOLD || BtnsToggle[btn]==TMHOLD+TON) { bLED[idx_LEDFH] =1; set_val(btn,100); }
    else if (BtnsFeature[btn]==FTURBOTN || BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTITN) {
      bLED[idx_LEDFTN]=1; set_val(btn,BtnTurboVal[TurboIdxN]);
    }
    else if (BtnsFeature[btn]==FTURBOTA || BtnsFeature[btn]==FMULTIDA || BtnsFeature[btn]==FMULTITA) {
      bLED[idx_LEDFTA]=1; set_val(btn,BtnTurboVal[TurboIdxA]);
    }
  }
 
  // active when the button is held down
  if (BtnsFeature[btn]==FTURBOHN && get_actual(btn)) { bLED[idx_LEDFTN]=1; set_val(btn,BtnTurboVal[TurboIdxN]); }
  if (BtnsFeature[btn]==FTURBOHA && get_actual(btn)) { bLED[idx_LEDFTA]=1; set_val(btn,BtnTurboVal[TurboIdxA]); }
}
 
// multi feature mode
void fMultiFeature(uint8 btn) {
  static uint8 block=FALSE; // block after toggle until next release
 
  if (event_release(btn)) block=FALSE;
 
    if (fTaps(btn,2,200,250)) { // tap+presshold
      block=TRUE;
      if (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA) BtnsToggle[btn]=TMTURBO+TON; // direct activation
      else if (BtnsFeature[btn]==FMULTITN || BtnsFeature[btn]==FMULTITA) BtnsToggle[btn]=TMTURBO+TOFF;  // req additional tap
      printDebug(TRUE,"")// output button_name, feature, toggle
      print("BUTTON_",FALSE,btn); print(" , "); print(FNAMES[BtnsFeature[btn]]); print(" , ");
      print(TNAMES[BtnsToggle[btn]]);
      printDebug(FALSE,NULL,TRUE);
    }
    if (!block && check_active(btn,1000)) { // hold
      block=TRUE;
      if (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA ) BtnsToggle[btn]=TMHOLD+TON; // direct activation
      else if (BtnsFeature[btn]==FMULTITN || BtnsFeature[btn]==FMULTITA) BtnsToggle[btn]=TMHOLD+TOFF; // req additional tap
      printDebug(TRUE,"")// output button_name, feature, toggle
      print("BUTTON_",FALSE,btn); print(" , "); print(FNAMES[BtnsFeature[btn]]); print(" , ");
      print(TNAMES[BtnsToggle[btn]]);
      printDebug(FALSE,NULL,TRUE);
    }
    // switch multi normal<->toggle(missunderstood) , btn+press Options
    if (get_actual(btn) && event_active(BUTTON_3)){
      if      (BtnsFeature[btn]==FMULTIDN) { BtnsFeature[btn]=FMULTITN; BtnsToggle[btn]=TOFF;}
      else if (BtnsFeature[btn]==FMULTITN) { BtnsFeature[btn]=FMULTIDN; BtnsToggle[btn]=TOFF;}
      else if (BtnsFeature[btn]==FMULTIDA) { BtnsFeature[btn]=FMULTITA; BtnsToggle[btn]=TOFF; }
      else if (BtnsFeature[btn]==FMULTITA) { BtnsFeature[btn]=FMULTIDA; BtnsToggle[btn]=TOFF;}
      //PrintNAME(FNAMES[BtnsFeature[btn]]); // output button_name and its feature
      printDebug(TRUE,"",FALSE)// output button_name, feature, toggle
      print("BUTTON_ , ",FALSE,btn); print(" , ");
      print(FNAMES[BtnsFeature[btn]]); print(" , "); print(TNAMES[BtnsToggle[btn]]);
      printDebug(FALSE,NULL,TRUE);
  }
}
 
// turbo<->altturbo
void fTurboModeFlip(uint8 btn) {
  if      (BtnsFeature[btn]==FTURBOHN) BtnsFeature[btn]=FTURBOHA; // hold
  else if (BtnsFeature[btn]==FTURBOHA) BtnsFeature[btn]=FTURBOHN;
  else if (BtnsFeature[btn]==FTURBOTN) BtnsFeature[btn]=FTURBOTA; // toggle
  else if (BtnsFeature[btn]==FTURBOTA) BtnsFeature[btn]=FTURBOTN;
  else if (BtnsFeature[btn]==FMULTIDN) BtnsFeature[btn]=FMULTIDA; // multi direct
  else if (BtnsFeature[btn]==FMULTIDA) BtnsFeature[btn]=FMULTIDN;
  else if (BtnsFeature[btn]==FMULTITN) BtnsFeature[btn]=FMULTITA; // multi toggle
  else if (BtnsFeature[btn]==FMULTITN) BtnsFeature[btn]=FMULTITA;
  //PrintNAME(FNAMES[BtnsFeature[btn]]); // output button_name and its feature
}
 
 
// adjust turbo press and release times
void fTurboAdjust() {
  // R1: TPress+10
  if (event_active(BUTTON_4) && TPress < 2000) { TPress += 10; }
  // L1: TPress-10
  if (event_active(BUTTON_7) && TPress > 20  ) { TPress -= 10; }
 
  // R2: TRelease+10
  if (event_active(BUTTON_5) && TRelease < 2000) { TRelease += 10; }
  // L2: TRelease-10
  if (event_active(BUTTON_8) && TRelease > 20  ) { TRelease -= 10;}
}
 
// reset turbo timings
void fTurboDefault() {
    TPress = 40;
    TRelease = 40;
    //fReset();
}
 
// sets current button value for the turbo modes to use when active
void fTurboTimer() {
  uint32 syst = system_time()
  static  uint32 TurboTimer=system_time();
  static  uint32 AltTurboTimer=0;
 
  if ( syst > TurboTimer && TurboTimer != 0 ) { // TURBO
    if (AltTurboTimer == 0 ) AltTurboTimer=TurboTimer + TPress + TRelease/2 - TPress/2;
    if ( syst > TurboTimer && syst <=TurboTimer+TPress ) BtnTurboVal[TurboIdxN]=100;
    else if ( syst > TurboTimer+TPress && syst < TurboTimer+TPress+TRelease) BtnTurboVal[TurboIdxN]=0;
    else if ( syst >= TurboTimer+TPress+TRelease) TurboTimer = syst;
  }
  if ( syst > AltTurboTimer && AltTurboTimer != 0 ) { // TURBO ALTERNATE
    if ( syst > AltTurboTimer && syst <=AltTurboTimer+TPress ) BtnTurboVal[TurboIdxA]=100;
    else if ( syst > AltTurboTimer+TPress && syst < AltTurboTimer+TPress+TRelease) BtnTurboVal[TurboIdxA]=0;
    else if ( syst >= AltTurboTimer+TPress+TRelease) AltTurboTimer = 0;
  }
}
 
 
void fQuickScope() {
  if (bQScope && time_active(QSBtns[QSCfg]) < QSTimeLimit && event_release(QSBtns[QSCfg]))    {
      combo_run(cQuickScope);
  }
}
 
combo cQuickScope {
    set_val(QSBtns[QSCfg], 100);
    wait(500);
    set_val(QSBtns[QSCfg], 100);
    set_val(QSBtns[QSCfg+1], 100);
    wait(50);
    set_val(QSBtns[QSCfg], 0);
    set_val(QSBtns[QSCfg+1], 0);
}
 
 
void fSensitivityAdjust() {
  // R1: TPress+10
  if (event_active(BUTTON_4) && RSensitivity < 200) { RSensitivity += 10; }
  // L1: TPress-10
  if (event_active(BUTTON_7) && LSensitivity < 200) { LSensitivity += 10; }
  // R2: TRelease+10
  if (event_active(BUTTON_5) && RSensitivity > 20)  { RSensitivity -= 10; }
  // L2: TRelease-10
  if (event_active(BUTTON_8) && LSensitivity > 20)  { LSensitivity -= 10; }
}
 
void fSensitivityDefault() {
    RSensitivity = 100;
    LSensitivity = 100;
}
 
// deadzone and sensitivity
void fSticks() {
  fDZSens(STICK_1_X,DeadZone,RSensitivity);
  fDZSens(STICK_1_Y,DeadZone,RSensitivity);
  fDZSens(STICK_2_X,DeadZone,LSensitivity);
  fDZSens(STICK_2_Y,DeadZone,LSensitivity);
 
}
 
void fDZSens(uint8 axis, fix32 dz,int16 sens) {
  if (abs(get_val(axis)) <= dz) {
      set_val(axis, 0.0);
  } else fSensitivity(axis, 50, sens);
}
 
void fSensitivity(uint8 id, int16 mid, int16 sen) {
    int16 val = (int16)get_val(id);
    if(mid != 0)    {
        int16 val_s = (val >= 0) ? 1 : -1;
        val *= val_s;
        if(val <= mid)    {
            val = (val * 50) / mid;
        }
        else {
            val = ((50 * (val - mid)) / (100 - mid)) + 50;
        }
        val *= val_s;
    }
    if(sen != 0)    {
        val = (val * sen) / 100;
    }
    set_val(id, clamp(val, -100, 100));
    return;
}
 
// cycle through output protocols
void fOutput() {
    static uint8 IOP=4;
    IOP=(IOP+1)%4;
 
    if (IOP == 0)    {
        fOutputProtocol(PIO_XB360);
    }
    if (IOP == 1)    {
        fOutputProtocol(PIO_PS3);
    }
    if (IOP == 2)    {
        fOutputProtocol(PIO_XB1);
    }
    if (IOP == 3)    {
        fOutputProtocol(PIO_PS4);
    }
}
 
// activate output protocol
void fOutputProtocol(uint8 id) {
    port_disconnect();
    switch(id)    {
        case PIO_PS3:
            port_connect(PORT_USB_C, PROTOCOL_PS3);
            printf("PROTOCOL_PS3");
            break;
        case PIO_XB360:
            port_connect(PORT_USB_C, PROTOCOL_XB360);
            printf("PROTOCOL_XB360");
            break;
        case PIO_PS4:
            port_connect(PORT_USB_C, PROTOCOL_PS4);
            printf("PROTOCOL_PS4");
            break;
        case PIO_XB1:
            port_connect(PORT_USB_C, PROTOCOL_XB1);
            printf("PROTOCOL_XB1");
            break;
        case PIO_SWITCH:
            port_connect(PORT_USB_C, PROTOCOL_SWITCH);
            printf("PROTOCOL_SWITCH");
            break;
    }
    return;
}
 
// check button tapped "taps" times, each press in the timelimit, with optional hold time check
uint8 fTaps(uint8 btn, uint8 taps, uint32 tlimit, uint32 thold) {
  static uint8 lastbtn=200, itaps=0;
  static uint32 lastta=0;
 
  if (event_active(btn)) {
    if (btn!=lastbtn || lastta+time_release(btn)>tlimit) { lastbtn=btn; itaps=1; }
    else if (btn==lastbtn) itaps++;   
    if (itaps==taps && !thold) { itaps=0; return TRUE; }
  }
  if (thold && check_active(btn,thold) && itaps==taps) {
    itaps=0;
    return TRUE;
  }
  if (event_release(btn) && btn==lastbtn) lastta=time_active(btn);
  return FALSE;
}
 
 
// block output
void fNullOutput() {
  set_val(BUTTON_1,0); set_val(BUTTON_2,0); set_val(BUTTON_3,0); set_val(BUTTON_4,0);
  set_val(BUTTON_5,0); set_val(BUTTON_6,0); set_val(BUTTON_7,0); set_val(BUTTON_8,0);
  set_val(BUTTON_9,0); set_val(BUTTON_10,0); set_val(BUTTON_11,0); set_val(BUTTON_12,0);
  set_val(BUTTON_13,0); set_val(BUTTON_14,0); set_val(BUTTON_15,0); set_val(BUTTON_16,0);
  set_val(BUTTON_17,0); set_val(BUTTON_18,0); set_val(BUTTON_19,0); set_val(BUTTON_20,0);
  set_val(BUTTON_21,0);
  set_val(STICK_1_X,0); set_val(STICK_1_Y,0); set_val(STICK_2_X,0); set_val(STICK_2_Y,0);
  set_val(POINT_1_X,0); set_val(POINT_1_Y,0); set_val(POINT_2_X,0); set_val(POINT_2_Y,0);
  set_val(ACCEL_1_X,0); set_val(ACCEL_1_Y,0); set_val(ACCEL_1_Z,0);
  set_val(ACCEL_2_X,0); set_val(ACCEL_2_Y,0); set_val(ACCEL_2_Z,0);
  set_val(GYRO_1_X,0); set_val(GYRO_1_Y,0); set_val(GYRO_1_Z,0);
}
 
void fDebug() {
  fDebugBtn();
  set_val(ACCEL_1_Z, TPress / 10);
  set_val(ACCEL_2_X, TRelease / 10);
  set_val(ACCEL_2_Z, CfgMode);
}
 
// last button pressed info
void fDebugBtn(uint8 btn) {
  //  Button_21 : BtnNr NN*1000 , Feature FF , Toggle TT/100
  static fix32 DebugBtn=9999.0;
 
  if (btn>0) {
    combo_stop(cDebugBtnTxt); // stop output of already queued debug text
    // device monitor value
    DebugBtn=(fix32)btn+1.0; // nr 16: name 17.0
    DebugBtn*=1000.0; // button name 17: 17000.00
    DebugBtn+=(fix32)BtnsFeature[btn]; // feature 170FF.00
    DebugBtn+=(fix32)BtnsToggle[btn]/100.0; // feature 170FF.00
 
    // output panel text output
    printDebug(TRUE);
    print("Button_",FALSE,btn);
    print(" , ");
    print(FNAMES[BtnsFeature[btn]]);
    print(" , ");
    print(TNAMES[BtnsToggle[btn]]);
    printDebug(FALSE,NULL,FALSE);
    combo_run(cDebugBtnTxt);
  }
 
  if (DebugBtn!=9999.0 && !btn) { // output
    set_val(BUTTON_21, DebugBtn);
  }
}
 
combo cDebugBtnTxt {
  wait(400);
  wait(0);
  print(NULL);
  wait(0);
}
 
// debug format
void printDebug(bool new,char *txt, bool send) {
#ifdef DebugTxtOutputPanel
  if (new) {
    print(NULL,TRUE);
    print("<b><font color='#00802b'>DEBUG</font></b> ");
  }
  if (txt) print(txt);
  if (send) print(NULL);
#endif
}
 
// based on J2Kbr magical printf in a single line
void print(char *str, bool clear, uint8 btn) {
#ifdef DebugTxtOutputPanel
  static char buffer[256], *tail;
  if (clear) {
    tail = NULL;
    memset(&buffer,0,sizeof(buffer));
    return;
  }
 
  if(str) {
      if(!tail) {
          tail = &buffer;
      }
      while(*str) {
          *tail++ = *str++;
      }
      if (btn) {
        *tail++ = (btn+1)/10+48; // 0,1,2,3 tens
        *tail++ = (btn+1)%10+48; // 0..9  ones
      }
  } else if(tail) {
      printf(&buffer);
      tail = NULL;
    memset(&buffer,0,sizeof(buffer));
  }
#endif
}
 
User avatar
Scachi
Brigadier General
Brigadier General
 
Posts: 3044
Joined: Wed May 11, 2016 6:25 am
Location: Germany

Re: Need help optimizing a script

Postby Fenria » Mon Feb 11, 2019 12:20 am

Ah, I was hoping for something like it being shown for every button at the same time, but I guess I didn't explain that properly.
My bad.

If it's not to much trouble, do you think you'd be able to change it so that when the script is in config mode, all the buttons show their current feature modes and toggle modes, with the feature mode using tens/hundreds coloumns, and the toggle mode using the ones coloumn?
User avatar
Fenria
Command Sergeant Major
Command Sergeant Major
 
Posts: 147
Joined: Thu May 21, 2015 5:56 pm

Re: Need help optimizing a script

Postby Scachi » Mon Feb 11, 2019 5:11 am

Fenria wrote:Ah, I was hoping for something like it being shown for every button at the same time, but I guess I didn't explain that properly.
My bad.

If it's not to much trouble, do you think you'd be able to change it so that when the script is in config mode, all the buttons show their current feature modes and toggle modes, with the feature mode using tens/hundreds coloumns, and the toggle mode using the ones coloumn?

Now it will show info of all the buttons in the Device Monitor BUTTON_ fields during cfg mode using the tens/hundreds like 71 for "feature 7 & state 1".
Entering cfgmode disables the output port to avoid sending the debug output to the console, you will get a disconnect controller message on your console. This is why I didn't do it for all buttons at first.
This is done to avoid sending the debug info to the console. On leaving the config mode it will reconnect the output connection.
I'll test another idea so we don't need to disable the output.

Code: Select all
#pragma METAINFO("Fenria Special", 0, 62, "")
 
#define DebugTxtOutputPanel // comment it to disable Debug Output Panel text
 
//  CONFIG MODE: 3x fast press TouchClick to enter and leave config mode
//   +DPAD-UP: CFGBTN_SCOPE   : button specific Turbo&Alternate&Hold AND quickscope  selection
//       -Double-Tap a button : to cycle through the available button specific features
//       -PS                  : clear all button features settings assignments and flags
//       -TouchClick Hold > 500ms: cycling through quickscope settings
//     +DEBUG via Device Monitor (on cfg mode only): Btn B, Feature F, Toggle T
//       -last pressed button information is written to BUTTON_21, Format: BB*1000 , FF , TT/100
//       -all button_ fields are displaying the btns selected features and toggle state, Format: FFT
//
//   +DPAD-RIGHT: CFGTURBO    : Turbo Timing adjustment
//       -PS : Turbo Timing reset
//
//   +DPAD-DOWN: CFGSENS_PROT : Sensitivity adjustment and Output Protocol selection
//        -Share : Output Protocol selection
//        -PS    : Sensitivity reset
 
//  Regular Usage:
//   + when using multi_func_toggle modes:
//      - holding the button + press Options will switch  "multi mode<->wrong multi mode"
//        my proposed/misunderstood multi_function_toggle version has no mode active by default
//        you have to select one with tap+press&hold or hold>1000ms. After that use a short tap to toggle it on/off
//        hold the button and tap share again to get back to the correct multi_func_toggle
//   + when using turbo modes:
//      - Buttonhold + Tap Share toggles turbo<->alt turbo
 
#include "ColorLED.gph"
 
// ++ BUTTON SPECIFIC FEATURES
//
// feature/mode identifier, for each button
#define FNONE     0  // no special function
#define FTURBOHN  1  // on hold = normal turbo
#define FTURBOTN  2  // tap = toggle normal turbo
#define FMULTIDN  3  // MULTI direct norm: dbltap+hold = turbo & hold>1sec = hold
#define FHOLD     4  // tap = toggle button hold
#define FTURBOHA  5  // on hold = alt turbo
#define FTURBOTA  6  // tap = toggle alt turbo
#define FMULTIDA  7  // MULTI direct alt: dbltap+hold = turbo&& hold>1sec = hold
#define F_MODES   8  // number of modes available to cycle through with dbl tap
#define FMULTITN  9  // MULTI tap alt : dbltap+hold = turbo & hold>1sec = hold , Btn+Share to toggle
#define FMULTITA  10 // MULTI tap norm: dbltap+hold = turbo & hold>1sec = hold , Btn+Share to toggle
 
// array used to output the feature name on feature selection cycling
char *FNAMES[] = {
  "Feature 00: NONE",
  "Feature 01: TURBO NORMAL HOLD",
  "Feature 02: TURBO NORMAL TAP",
  "Feature 03: MULTI NORMAL TURBO & HOLD",
  "Feature 04: SIMPLE HOLD TAP",
  "Feature 05: TURBO ALT HOLD",
  "Feature 06: TURBO ALT TAP",
  "Feature 07: MULTI ALT TURBO & HOLD",
  "Feature 08: NOT USED",
  "Feature 09: MULTI TAP NORMAL TURBO & HOLD",
  "Feature 10: MULTI TAP ALT TURBO & HOLD",
};
 
// LED blink colors for feature toggles
uint8 LEDF[] = {
  CP,  // pink   on FNONE / Non special mode
  CB,  // blue   on FTURBOHN (hold,normal)     
  CA,  // amber  on FTURBOTN (toggle,normal)   
  CC,  // cyan   on FMULTIDN & FMULTITN
  CG,  // green  on FHOLD                     
  CR,  // red    on FTURBOHA (hold,alternate) 
  CW,  // white  on FTURBOTA (toggle,alternate)
  CC,  // cyan   on FMULTIDA & FMULTITA
};
 
// ++ LED Feedback state tracking flags in RGB order , position in array
#define idx_LEDFTA  0  // FTURBOA (alternate) +blink on active
#define idx_LEDFH   1  // FHOLD               +static on active
#define idx_LEDFTN  2  // FTURBON (normal)    +blink on active
bool bLED[] = { FALSE,FALSE,FALSE, };
 
 
// toggle state ids
#define TOFF      0   // toggled off
#define TON       1   // toggled on
#define TMTURBO   2   // multi turbo
#define TMHOLD    4   // multi hold
#define T_MODES   2   // for state checking using % modulo
 
// array used to output the toggle state name on change
char *TNAMES[] = {
  "State 00: TOFF",
  "State 01: TON",
  "State 02: TMTURBO",
  "State 03: TMTURBO+TON", // multi toggle
  "State 04: TMHOLD",      // multi toggle
  "State 05: TMHOLD+TON",  // multi toggle
};
 
 
uint8 BtnsFeature[21];// buttons feature flags (FNONE, FTURBOHN, ...)
uint8 BtnsToggle[21]; // buttons feature toggle state (TOFF,TON,...)
uint8 BtnTurboVal[2]; // buttons value to set for 0:turbo, 1:alt turbo, set by function fTurboTimer
#define TurboIdxN 0   // normal turbo is at this index in BtnTurboVal
#define TurboIdxA 1   // alternate turbo is at this index in BtnTurboVal
 
int16 TPress  =60// turbo button press time
int16 TRelease=60// turbo button release time
 
 
// ++ GENERAL FEATURES - non button specific
//
// ######## Quick Scope
bool bQScope =0; // quick scope state flag
uint32 QSTimeLimit=100; // timelimit of press time for starting quickscope combo
              //  scope    , fire
uint8 QSBtns[8] ={BUTTON_8 ,BUTTON_5//  L2 & R2 default
                  BUTTON_6 ,BUTTON_5//  R3 & R2
                  BUTTON_17,BUTTON_5//  Square & R2
                  200      ,200     ,  //  dummy for off state
                  };
uint8 QSCfg =6; // quickscope button pair to use 0,2,4,6 (6==off)
 
 
// ######## Stick Sensitivity and Deadzone
fix32 DeadZone=10.0;
int16 RSensitivity=100; // right stick sensitivity
int16 LSensitivity=100; // left  stick sensitivity
 
 
// ######## Output Protocol
#define PIO_NONE    0
#define PIO_AUTO    0
#define PIO_PS4     4
#define PIO_PS3     1
#define PIO_XB1     5
#define PIO_XB360   2
#define PIO_WII     3
#define PIO_HID     6
#define PIO_SWITCH  7
 
 
// ++ Configuration Mode
bool bConfigure=FALSE;
uint8 CfgMode =0;
#define CFGNONE       0 // no config sub entry (1,2,3) selected
#define CFGBTN_SCOPE  1
#define CFGTURBO      2
#define CFGSENS_PROT  3
 
char *CNAMES[]={
  "CfgMode 0: CFGNONE      = Main Cfg Menu",
  "CfgMode 1: CFGBTN_SCOPE = Btn Features & Quickscope",
  "CfgMode 2: CFGTURBO     = Turbo Timing",
  "CfgMode 3: CFGSENS_PROT = Sensitivity & Output Protocol",
};
 
// led feedback for configuration menu position
#define LCFGENTER 0
#define LCFGLEAVE 0
uint8 LEDCFG[] = {
  CP, // pink , entering+leaving config mode
};
 
init {
  // for testing
  /*
  TPress  =200;  // turbo button press time
  TRelease=200;  // turbo button release time
  BtnsFeature[BUTTON_10]=FHOLD; // hold feature
  BtnsFeature[BUTTON_5]=FTURBOHN; // turbo feature normal
  BtnsFeature[BUTTON_8]=FTURBOHA; // turbo feature alternate
  */

  /*
  bConfigure=TRUE;
  CfgMode=CFGBTN_SCOPE;
  */

}
 
main {
  // reset led flags
  bLED[0]=FALSE; bLED[1]=FALSE; bLED[2]=FALSE;
 
  fConfigToggle();
 
  if (bConfigure) {
      fConfigure(); // handling configuration logic
      if (elapsed_time()) { // TESTING: lower cpu usage, remove this when output gets through
        //fNullOutput();      // zero output via set_val
        fNullUnused();      // zero buttons/input only that can't have features assigned
        fDebug();           // debug output via set_val
      }
  } else {
      fButtons();   // buttons specific feature toggle and usage: hold, turbo hold, turbo toggle
      static uint32 etime=0; etime+=elapsed_time();
      if (etime > 5) {
        etime=0; fButtonLED(); // usage led feedback
      }
  }
 
  // ## always active stuff
  if (elapsed_time()) { // TESTING: lower cpu usage, this one should be fine as it uses no event_ stuff
    fTurboTimer(); // turbo and alternate turbo time tracker, sets values of array BtnTurboVal
  }
  fQuickScope(); // quick scope
  fSticks(); // stick deadzone and sensitivity
}
 
 
// button feature activity LED feedback
void fButtonLED() {
  // bLED[0] is hold feature,             green = LED_3
  // bLED[1] is turbo(normal) feature,    blue  = LED_1
  // bLED[2] is turbo(alternate) feature, red   = LED_2
  static bool bIdle=FALSE;
  static uint8 LastState[3]={2, 2, 2};
  static uint8 LastVal[3]= {2, 2, 2};
 
  // state change test
  if (LastState[0]!=bLED[0] || LastState[1]!=bLED[1] || LastState[2]!=bLED[2]) {
    LastState[0]=bLED[0]; LastState[1]=bLED[1]; LastState[2]=bLED[2]; // reset
    //printf("State changed");
 
    if (!(bLED[0] + bLED[1] + bLED[2])) { // idle
      bIdle=TRUE;
      ColorLED(LEDF[FNONE]); // pink led
      //printf("LED State: normal == idle == pink"); 
    } else { // busy
      bIdle=FALSE;
      LastVal[0]=2; LastVal[1]=2; LastVal[2]=2// reset
      //printf("LED State: busy");
    }
  } // eo: state change test
 
  if (!bIdle) { // not idle...set color according to active features
 
    // bLED[0] is hold feature ,            green = LED_3
    if (LastVal[idx_LEDFH]!=bLED[idx_LEDFH]) {
      LastVal[idx_LEDFH]=bLED[idx_LEDFH];
      led_set(LED_4,0.0,0);
      led_set(LED_3,(fix32)bLED[idx_LEDFH]*100f,0);
      //printf("led3: %d",LastVal[idx_LEDFH]);
 
 
    }
 
    // bLED[1] is turbo(normal) feature,    blue  = LED_1
    if (LastVal[idx_LEDFTN]!=bLED[idx_LEDFTN]*BtnTurboVal[TurboIdxN]) {
      LastVal[idx_LEDFTN]=bLED[idx_LEDFTN]*BtnTurboVal[TurboIdxN];
      led_set(LED_4,0.0,0);
      led_set(LED_1,(fix32)LastVal[idx_LEDFTN],0);     
      //printf("led1: %d",LastVal[idx_LEDFTN]);
    }
 
    // bLED[2] is turbo(alternate) feature, red   = LED_2
    if (LastVal[idx_LEDFTA]!=bLED[idx_LEDFTA]*BtnTurboVal[TurboIdxA]) {
      LastVal[idx_LEDFTA]=bLED[idx_LEDFTA]*BtnTurboVal[TurboIdxA];
      led_set(LED_4,0.0,0);
      led_set(LED_2,(fix32)LastVal[idx_LEDFTA],0);
      //printf("led2: %d",LastVal[idx_LEDFTA]);
    }
 
    // feature are selected and active but only one turbo is used, set non-turbo time to pink
    if (LastState[idx_LEDFH]==0 && LastVal[idx_LEDFTN]==0 && LastVal[idx_LEDFTA]==0) {
      ColorLED(LEDF[FNONE]); // pink led
    }
  }
}
 
// toggle configuration mode
void fConfigToggle() {
  if (event_active(BUTTON_2) || event_release(BUTTON_2)) { // less cpu usage
    if (fTaps(BUTTON_2,3,250)) {
      bConfigure=!bConfigure;
      CfgMode=CFGNONE; // set active submenu to none
 
      // CfgMode toggle notification
      if (bConfigure) {
        ColorLED(LEDCFG[LCFGENTER],140,140,3,LEDF[FNONE]);
        printDebug(TRUE,"CfgMode 0 : Entered = Main Menu",TRUE);
        port_disconnect();
      } else {
        ColorLED(LEDCFG[LCFGLEAVE],140,140,3,LEDF[FNONE]);
        printDebug(TRUE,"CfgMode Exited",TRUE);
        fOutputProtocol();
      }
    } // eo: tripple click
  }
}
 
// doing the configuration
void fConfigure() {
    static bool TClicked=FALSE; // for trigger quickscope button layout cycle with longer button hold
 
    if (CfgMode==CFGNONE) { // no sub entry selected
      if (event_active(BUTTON_10)) {
        CfgMode=CFGBTN_SCOPE;
        printDebug(TRUE,CNAMES[CfgMode],TRUE);
      }
      if (event_active(BUTTON_13)) {
        CfgMode=CFGTURBO;
        printDebug(TRUE,CNAMES[CfgMode],TRUE);
      }
      if (event_active(BUTTON_11)) {
        CfgMode=CFGSENS_PROT;
        printDebug(TRUE,CNAMES[CfgMode],TRUE);
        }
    } // eo: CfgMode==CFGNONE
 
    else { // ## in sub entry
      if (event_active(BUTTON_3)) {
        CfgMode=CFGNONE; // back to main entry
        printDebug(TRUE,CNAMES[CfgMode],TRUE);
        ColorLED(LEDCFG[0],140,140,3,LEDF[FNONE]);
      }
 
      switch(CfgMode) { // sub entry specific
        case CFGBTN_SCOPE:  // button feature and quickscope selection
                if (event_active(BUTTON_1)) fDefaultFeatures(); // PS button
                else {
                  fButtons(TRUE); // TRUE for feature selection
                  if (event_release(BUTTON_2)) TClicked=FALSE;
                  if (check_active(BUTTON_2,500) && !TClicked) {
                    TClicked=TRUE;
                    QSCfg=(QSCfg+2)%8;
                    if (QSCfg>=6) bQScope=FALSE; else bQScope=TRUE;
                    //printf("quickscope (1:on/0:off) %d ,Button layout idx: %d, scope: Btn_%d, fire: Btn_%d",bQScope,QSCfg,QSBtns[QSCfg]+1,QSBtns[QSCfg+1]+1);
                    printDebug(TRUE,"Quickscope , enabled=");
                    if (bQScope) print("TRUE"); else print("FALSE");
                    print(" , Scope Btn_",FALSE,QSBtns[QSCfg]+1); print(" , Fire Btn_",FALSE,QSBtns[QSCfg+1]+1);
                    print(NULL);
                  }
                }
          break;
        case CFGTURBO:      // button turbo timing adjustment
                if (event_active(BUTTON_1)) fTurboDefault(); // PS button
                else fTurboAdjust();
          break;
        case CFGSENS_PROT:  // sensitivity and output protocol adjustment
                if (event_active(BUTTON_18)) fOutput(); // Share : change output protocol
                if (event_active(BUTTON_1)) fSensitivityDefault(); // PS button
                else fSensitivityAdjust();
          break;
      }
    }
}
 
 
// button loop for config and usage
void fButtons(bool cfg) {
  uint8 btn;
 
  for (btn=BUTTON_4;btn<=BUTTON_17;btn++) {  // buttons PS4: R1...Square
    // reduces cpu usage
    if ( !event_active(btn) && !event_release(btn) && !get_actual(btn) && !BtnsToggle[btn]==TON ) continue;
 
    if (cfg) fBtnSelect(btn); // select buttons feature                   
    else fBtnUsage(btn);      // use buttons feature
  }
}
 
// clear all button features assignments and quick scope
void fDefaultFeatures() {
  uint8 btn;
  for (btn=BUTTON_4;btn<=BUTTON_17;btn++) { // buttons PS4: R1..Square
    BtnsFeature[btn]=FNONE;
    BtnsToggle[btn]=TOFF;
  }
  QSCfg=6;
  bQScope=FALSE;
}
 
// select feature for the button
void fBtnSelect(uint8 btn) {
    // cycle through modes with dbl tap 
    if (fTaps(btn,2,250)) {
      BtnsFeature[btn]=(BtnsFeature[btn]+1)%F_MODES;
      BtnsToggle[btn]=TOFF; // toggle state reset
 
      if (BtnsFeature[btn] < F_MODES ) { // led toggle feedback
        fDebugBtn(btn);
        if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(BtnsFeature[btn],200,200,2,LEDF[FNONE]);
      }
    }
 
    // update debug info for current button
    if (event_active(btn)) fDebugBtn(btn);
}
 
// use buttons selected features
void fBtnUsage(uint8 btn) {
 
  // Button feature ON/OFF toggle with short tap
  if (BtnsFeature[btn]!=FNONE && event_release(btn) && time_active(btn) <=250) {
    if (BtnsToggle[btn]%T_MODES==TOFF) {
      BtnsToggle[btn]+=TON; // sets 1,3,5 (3,5 for multi toggle)
      if (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA) BtnsToggle[btn]=TOFF;
      if ((BtnsFeature[btn]==FMULTITN || BtnsFeature[btn]==FMULTITA) && BtnsToggle[btn] < T_MODES) BtnsToggle[btn]=TOFF;
    } else if (BtnsToggle[btn]%T_MODES==TON) {                       // disable
      if (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA) BtnsToggle[btn]=TOFF;
      else BtnsToggle[btn]-=TON; // sets 0,2,4 (2,4 for multi org)
    }
  }
 
  // Buttonhold + press Share toggles turbo<->alt turbo
  if (get_actual(btn)) {
    set_val(BUTTON_3,0);set_val(BUTTON_18,0); // block share & options
    if (event_active(BUTTON_18)) fTurboModeFlip(btn);
  }
 
  // multi feature mode : tap+presshold = turbo || hold>1sec = hold
  if (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA || BtnsFeature[btn]==FMULTITN || BtnsFeature[btn]==FMULTITA) {
    if (event_release(btn) || event_active(btn) || get_actual(btn)) fMultiFeature(btn);
  }
 
  // feature with toggle
  if (BtnsToggle[btn]%T_MODES==TON) {
    if (BtnsFeature[btn]==FHOLD || BtnsToggle[btn]==TMHOLD+TON) { bLED[idx_LEDFH] =1; set_val(btn,100); }
    else if (BtnsFeature[btn]==FTURBOTN || BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTITN) {
      bLED[idx_LEDFTN]=1; set_val(btn,BtnTurboVal[TurboIdxN]);
    }
    else if (BtnsFeature[btn]==FTURBOTA || BtnsFeature[btn]==FMULTIDA || BtnsFeature[btn]==FMULTITA) {
      bLED[idx_LEDFTA]=1; set_val(btn,BtnTurboVal[TurboIdxA]);
    }
  }
 
  // active when the button is held down
  if (BtnsFeature[btn]==FTURBOHN && get_actual(btn)) { bLED[idx_LEDFTN]=1; set_val(btn,BtnTurboVal[TurboIdxN]); }
  if (BtnsFeature[btn]==FTURBOHA && get_actual(btn)) { bLED[idx_LEDFTA]=1; set_val(btn,BtnTurboVal[TurboIdxA]); }
}
 
// multi feature mode
void fMultiFeature(uint8 btn) {
  static uint8 block=FALSE; // block after toggle until next release
 
  if (event_release(btn)) block=FALSE;
 
    if (fTaps(btn,2,200,250)) { // tap+presshold
      block=TRUE;
      if (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA) BtnsToggle[btn]=TMTURBO+TON; // direct activation
      else if (BtnsFeature[btn]==FMULTITN || BtnsFeature[btn]==FMULTITA) BtnsToggle[btn]=TMTURBO+TOFF;  // req additional tap
      printDebug(TRUE,"")// output button_name, feature, toggle
      print("BUTTON_",FALSE,btn); print(" , "); print(FNAMES[BtnsFeature[btn]]); print(" , ");
      print(TNAMES[BtnsToggle[btn]]);
      printDebug(FALSE,NULL,TRUE);
    }
    if (!block && check_active(btn,1000)) { // hold
      block=TRUE;
      if (BtnsFeature[btn]==FMULTIDN || BtnsFeature[btn]==FMULTIDA ) BtnsToggle[btn]=TMHOLD+TON; // direct activation
      else if (BtnsFeature[btn]==FMULTITN || BtnsFeature[btn]==FMULTITA) BtnsToggle[btn]=TMHOLD+TOFF; // req additional tap
      printDebug(TRUE,"")// output button_name, feature, toggle
      print("BUTTON_",FALSE,btn); print(" , "); print(FNAMES[BtnsFeature[btn]]); print(" , ");
      print(TNAMES[BtnsToggle[btn]]);
      printDebug(FALSE,NULL,TRUE);
    }
    // switch multi normal<->toggle(missunderstood) , btn+press Options
    if (get_actual(btn) && event_active(BUTTON_3)){
      if      (BtnsFeature[btn]==FMULTIDN) { BtnsFeature[btn]=FMULTITN; BtnsToggle[btn]=TOFF;}
      else if (BtnsFeature[btn]==FMULTITN) { BtnsFeature[btn]=FMULTIDN; BtnsToggle[btn]=TOFF;}
      else if (BtnsFeature[btn]==FMULTIDA) { BtnsFeature[btn]=FMULTITA; BtnsToggle[btn]=TOFF; }
      else if (BtnsFeature[btn]==FMULTITA) { BtnsFeature[btn]=FMULTIDA; BtnsToggle[btn]=TOFF;}
      //PrintNAME(FNAMES[BtnsFeature[btn]]); // output button_name and its feature
      printDebug(TRUE,"",FALSE)// output button_name, feature, toggle
      print("BUTTON_ , ",FALSE,btn); print(" , ");
      print(FNAMES[BtnsFeature[btn]]); print(" , "); print(TNAMES[BtnsToggle[btn]]);
      printDebug(FALSE,NULL,TRUE);
  }
}
 
// turbo<->altturbo
void fTurboModeFlip(uint8 btn) {
  if      (BtnsFeature[btn]==FTURBOHN) BtnsFeature[btn]=FTURBOHA; // hold
  else if (BtnsFeature[btn]==FTURBOHA) BtnsFeature[btn]=FTURBOHN;
  else if (BtnsFeature[btn]==FTURBOTN) BtnsFeature[btn]=FTURBOTA; // toggle
  else if (BtnsFeature[btn]==FTURBOTA) BtnsFeature[btn]=FTURBOTN;
  else if (BtnsFeature[btn]==FMULTIDN) BtnsFeature[btn]=FMULTIDA; // multi direct
  else if (BtnsFeature[btn]==FMULTIDA) BtnsFeature[btn]=FMULTIDN;
  else if (BtnsFeature[btn]==FMULTITN) BtnsFeature[btn]=FMULTITA; // multi toggle
  else if (BtnsFeature[btn]==FMULTITN) BtnsFeature[btn]=FMULTITA;
  //PrintNAME(FNAMES[BtnsFeature[btn]]); // output button_name and its feature
}
 
 
// adjust turbo press and release times
void fTurboAdjust() {
  // R1: TPress+10
  if (event_active(BUTTON_4) && TPress < 2000) { TPress += 10; }
  // L1: TPress-10
  if (event_active(BUTTON_7) && TPress > 20  ) { TPress -= 10; }
 
  // R2: TRelease+10
  if (event_active(BUTTON_5) && TRelease < 2000) { TRelease += 10; }
  // L2: TRelease-10
  if (event_active(BUTTON_8) && TRelease > 20  ) { TRelease -= 10;}
}
 
// reset turbo timings
void fTurboDefault() {
    TPress = 40;
    TRelease = 40;
    //fReset();
}
 
// sets current button value for the turbo modes to use when active
void fTurboTimer() {
  uint32 syst = system_time()
  static  uint32 TurboTimer=system_time();
  static  uint32 AltTurboTimer=0;
 
  if ( syst > TurboTimer && TurboTimer != 0 ) { // TURBO
    if (AltTurboTimer == 0 ) AltTurboTimer=TurboTimer + TPress + TRelease/2 - TPress/2;
    if ( syst > TurboTimer && syst <=TurboTimer+TPress ) BtnTurboVal[TurboIdxN]=100;
    else if ( syst > TurboTimer+TPress && syst < TurboTimer+TPress+TRelease) BtnTurboVal[TurboIdxN]=0;
    else if ( syst >= TurboTimer+TPress+TRelease) TurboTimer = syst;
  }
  if ( syst > AltTurboTimer && AltTurboTimer != 0 ) { // TURBO ALTERNATE
    if ( syst > AltTurboTimer && syst <=AltTurboTimer+TPress ) BtnTurboVal[TurboIdxA]=100;
    else if ( syst > AltTurboTimer+TPress && syst < AltTurboTimer+TPress+TRelease) BtnTurboVal[TurboIdxA]=0;
    else if ( syst >= AltTurboTimer+TPress+TRelease) AltTurboTimer = 0;
  }
}
 
 
void fQuickScope() {
  if (bQScope && time_active(QSBtns[QSCfg]) < QSTimeLimit && event_release(QSBtns[QSCfg]))    {
      combo_run(cQuickScope);
  }
}
 
combo cQuickScope {
    set_val(QSBtns[QSCfg], 100);
    wait(500);
    set_val(QSBtns[QSCfg], 100);
    set_val(QSBtns[QSCfg+1], 100);
    wait(50);
    set_val(QSBtns[QSCfg], 0);
    set_val(QSBtns[QSCfg+1], 0);
}
 
 
void fSensitivityAdjust() {
  // R1: TPress+10
  if (event_active(BUTTON_4) && RSensitivity < 200) { RSensitivity += 10; }
  // L1: TPress-10
  if (event_active(BUTTON_7) && LSensitivity < 200) { LSensitivity += 10; }
  // R2: TRelease+10
  if (event_active(BUTTON_5) && RSensitivity > 20)  { RSensitivity -= 10; }
  // L2: TRelease-10
  if (event_active(BUTTON_8) && LSensitivity > 20)  { LSensitivity -= 10; }
}
 
void fSensitivityDefault() {
    RSensitivity = 100;
    LSensitivity = 100;
}
 
// deadzone and sensitivity
void fSticks() {
  fDZSens(STICK_1_X,DeadZone,RSensitivity);
  fDZSens(STICK_1_Y,DeadZone,RSensitivity);
  fDZSens(STICK_2_X,DeadZone,LSensitivity);
  fDZSens(STICK_2_Y,DeadZone,LSensitivity);
 
}
 
void fDZSens(uint8 axis, fix32 dz,int16 sens) {
  if (abs(get_val(axis)) <= dz) {
      set_val(axis, 0.0);
  } else fSensitivity(axis, 50, sens);
}
 
void fSensitivity(uint8 id, int16 mid, int16 sen) {
    int16 val = (int16)get_val(id);
    if(mid != 0)    {
        int16 val_s = (val >= 0) ? 1 : -1;
        val *= val_s;
        if(val <= mid)    {
            val = (val * 50) / mid;
        }
        else {
            val = ((50 * (val - mid)) / (100 - mid)) + 50;
        }
        val *= val_s;
    }
    if(sen != 0)    {
        val = (val * sen) / 100;
    }
    set_val(id, clamp(val, -100, 100));
    return;
}
 
// cycle through output protocols
void fOutput() {
    static uint8 IOP=4;
    IOP=(IOP+1)%4;
 
    if (IOP == 0)    {
        fOutputProtocol(PIO_XB360);
    }
    if (IOP == 1)    {
        fOutputProtocol(PIO_PS3);
    }
    if (IOP == 2)    {
        fOutputProtocol(PIO_XB1);
    }
    if (IOP == 3)    {
        fOutputProtocol(PIO_PS4);
    }
}
 
// activate output protocol
void fOutputProtocol(uint8 id) {
    static uint8 LastProtocol=0; // reconnecting after config mode using the last procotol
    if (!id) LastProtocol=id;
    else id=LastProtocol;
 
    if(bConfigure) return; // don't change it during config, doing it now on exit of configmode
 
    //port_disconnect();
    switch(id)    {
        case PIO_PS3:
            port_connect(PORT_USB_C, PROTOCOL_PS3);
            printDebug(TRUE,"PROTOCOL_PS3",TRUE);
            break;
        case PIO_XB360:
            port_connect(PORT_USB_C, PROTOCOL_XB360);
            printDebug(TRUE,"PROTOCOL_XB360",TRUE);
            break;
        case PIO_PS4:
            port_connect(PORT_USB_C, PROTOCOL_PS4);
            printDebug(TRUE,"PROTOCOL_PS4",TRUE);
            break;
        case PIO_XB1:
            port_connect(PORT_USB_C, PROTOCOL_XB1);
            printDebug(TRUE,"PROTOCOL_XB1",TRUE);
            break;
        case PIO_SWITCH:
            port_connect(PORT_USB_C, PROTOCOL_SWITCH);
            printDebug(TRUE,"PROTOCOL_SWITCH",TRUE);
            break;
        default:
            port_connect(PORT_USB_C, PROTOCOL_AUTO);
            printDebug(TRUE,"PROTOCOL_AUTO",TRUE);
    }
    return;
}
 
// check button tapped "taps" times, each press in the timelimit, with optional hold time check
uint8 fTaps(uint8 btn, uint8 taps, uint32 tlimit, uint32 thold) {
  static uint8 lastbtn=200, itaps=0;
  static uint32 lastta=0;
 
  if (event_active(btn)) {
    if (btn!=lastbtn || lastta+time_release(btn)>tlimit) { lastbtn=btn; itaps=1; }
    else if (btn==lastbtn) itaps++;   
    if (itaps==taps && !thold) { itaps=0; return TRUE; }
  }
  if (thold && check_active(btn,thold) && itaps==taps) {
    itaps=0;
    return TRUE;
  }
  if (event_release(btn) && btn==lastbtn) lastta=time_active(btn);
  return FALSE;
}
 
 
// block output
void fNullOutput() {
  set_val(BUTTON_1,0); set_val(BUTTON_2,0); set_val(BUTTON_3,0); set_val(BUTTON_4,0);
  set_val(BUTTON_5,0); set_val(BUTTON_6,0); set_val(BUTTON_7,0); set_val(BUTTON_8,0);
  set_val(BUTTON_9,0); set_val(BUTTON_10,0); set_val(BUTTON_11,0); set_val(BUTTON_12,0);
  set_val(BUTTON_13,0); set_val(BUTTON_14,0); set_val(BUTTON_15,0); set_val(BUTTON_16,0);
  set_val(BUTTON_17,0); set_val(BUTTON_18,0); set_val(BUTTON_19,0); set_val(BUTTON_20,0);
  set_val(BUTTON_21,0);
  set_val(STICK_1_X,0); set_val(STICK_1_Y,0); set_val(STICK_2_X,0); set_val(STICK_2_Y,0);
  set_val(POINT_1_X,0); set_val(POINT_1_Y,0); set_val(POINT_2_X,0); set_val(POINT_2_Y,0);
  set_val(ACCEL_1_X,0); set_val(ACCEL_1_Y,0); set_val(ACCEL_1_Z,0);
  set_val(ACCEL_2_X,0); set_val(ACCEL_2_Y,0); set_val(ACCEL_2_Z,0);
  set_val(GYRO_1_X,0); set_val(GYRO_1_Y,0); set_val(GYRO_1_Z,0);
}
 
void fNullUnused() {
  set_val(BUTTON_1,0); set_val(BUTTON_2,0); set_val(BUTTON_3,0);
  set_val(BUTTON_18,0); set_val(BUTTON_19,0); set_val(BUTTON_20,0); set_val(BUTTON_21,0);
  set_val(STICK_1_X,0); set_val(STICK_1_Y,0); set_val(STICK_2_X,0); set_val(STICK_2_Y,0);
  set_val(POINT_1_X,0); set_val(POINT_1_Y,0); set_val(POINT_2_X,0); set_val(POINT_2_Y,0);
  set_val(ACCEL_1_X,0); set_val(ACCEL_1_Y,0); set_val(ACCEL_1_Z,0);
  set_val(ACCEL_2_X,0); set_val(ACCEL_2_Y,0); set_val(ACCEL_2_Z,0);
  set_val(GYRO_1_X,0); set_val(GYRO_1_Y,0); set_val(GYRO_1_Z,0);
}
 
void fDebug() {
  if (elapsed_time()) {
  fDebugBtn();
  fDebugBtns();
  set_val(ACCEL_1_Z, TPress / 10);
  set_val(ACCEL_2_X, TRelease / 10);
  set_val(ACCEL_2_Z, CfgMode);
  }
}
 
void fDebugBtns() {
  uint8 btn;
  for (btn=BUTTON_4;btn<=BUTTON_17;btn++) {
    set_val(btn,BtnsFeature[btn]*10+BtnsToggle[btn]);
  }
}
 
// last button pressed info
void fDebugBtn(uint8 btn) {
  //  Button_21 : BtnNr NN*1000 , Feature FF , Toggle TT/100
  static fix32 DebugBtn=9999.0;
 
  if (btn>0) {
    combo_stop(cDebugBtnTxt); // stop output of already queued debug text
    // device monitor value
    DebugBtn=(fix32)btn+1.0; // nr 16: name 17.0
    DebugBtn*=1000.0; // button name 17: 17000.00
    DebugBtn+=(fix32)BtnsFeature[btn]; // feature 170FF.00
    DebugBtn+=(fix32)BtnsToggle[btn]/100.0; // feature 170FF.00
 
    // output panel text output
    printDebug(TRUE);
    print("Button_",FALSE,btn);
    print(" , ");
    print(FNAMES[BtnsFeature[btn]]);
    print(" , ");
    print(TNAMES[BtnsToggle[btn]]);
    printDebug(FALSE,NULL,FALSE);
    combo_run(cDebugBtnTxt);
  }
 
  if (DebugBtn!=9999.0 && !btn) { // output
    set_val(BUTTON_21, DebugBtn);
  }
}
 
combo cDebugBtnTxt {
  wait(250);
  wait(0);
  print(NULL);
  wait(0);
}
 
// debug format
void printDebug(bool new,char *txt, bool send) {
#ifdef DebugTxtOutputPanel
  if (new) {
    print(NULL,TRUE);
    print("<b><font color='#00802b'>DEBUG</font></b> ");
  }
  if (txt) print(txt);
  if (send) print(NULL);
#endif
}
 
// based on J2Kbr magical printf in a single line
void print(char *str, bool clear, uint8 btn) {
#ifdef DebugTxtOutputPanel
  static char buffer[256], *tail;
  if (clear) {
    tail = NULL;
    memset(&buffer,0,sizeof(buffer));
    return;
  }
 
  if(str) {
      if(!tail) {
          tail = &buffer;
      }
      while(*str) {
          *tail++ = *str++;
      }
      if (btn) {
        *tail++ = (btn+1)/10+48; // 0,1,2,3 tens
        *tail++ = (btn+1)%10+48; // 0..9  ones
      }
  } else if(tail) {
      printf(&buffer);
      tail = NULL;
    memset(&buffer,0,sizeof(buffer));
  }
#endif
}
 
User avatar
Scachi
Brigadier General
Brigadier General
 
Posts: 3044
Joined: Wed May 11, 2016 6:25 am
Location: Germany

PreviousNext

Return to GPC2 Script Programming

Who is online

Users browsing this forum: No registered users and 136 guests