Need help optimizing a script

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

Re: Need help optimizing a script

Postby Fenria » Tue Feb 12, 2019 4:52 pm

Cool, I'll give it a test just to make sure that no other issues pop up.

Edit:
I tested the script with #define _ColorBrightness added, and everything seems to work fine.

Thanks for figuring out what was causing the issue and telling me how to fix it.

Edit 2:
I was looking through the code and noticed that you have LED indicators for what function is being assigned to a button, and I realized that the LEDs that blink don't match with what the LEDF array says they should for some reason.

It instead always goes blinking blue -> solid blue -> blinking pink -> blinking green-> blinking red -> blinking blue -> solid blue -> blinking red, then cycles back to the first blinking blue.
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 » Wed Feb 13, 2019 8:24 am

About the led, thanks for reporting it..I missed to use the LEDF array in this command.

Code: Select all
 
// wrong: It uses the buttons selected featureID directly
ColorLED(BtnsFeature[btn],200,200,2,LEDF[FNONE]);
 
// correct:  translates the Feature ID to colorID by using LEDF array
ColorLED(LEDF[BtnsFeature[btn]],200,200,2,LEDF[FNONE]);
 


Here is the fixed version along with the option to display the last buttons assigned feature and toggle via Device Monitor outside of config mode.
It is enabled and uses BUTTON_21 by default but can be adjusted with the defines at the beginning of the script :
#define BtnValTo BUTTON_21
#define BtnValInfo TRUE

You can also disable text output by category easily by changing true->false in the TXTSelect array.

Code: Select all
#pragma METAINFO("Fenria Special", 0, 7, "")
 
//  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: 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 via the Output Panel
//
//   +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
 
// DEBUG settings
//
bool TXTSelect[]={ // enable/disable output panel text messages per type
        TRUE//  TXTMENU   // menu navigation
        TRUE , //  TXTFEAT   // two-line feature status summary output
        TRUE//  TXTPROT   // output protocol
        FALSE, //  TXTLED    // led feedback
        TRUE//  TXTFSEL   // button feature selection
        TRUE//  TXTFCUR   // show current features name on a single press
};
#define BtnValInfo  TRUE      // show feature and toggle state in Device Monitor  // TRUE - FALSE
#define BtnValTo    BUTTON_21 // <-     at this position        --^
 
#define _ColorBrightness
#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: USED INTERNALY",
  "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     0  // no special function
  CB,  // blue   on FTURBOHN  1  // on hold = normal turbo
  CA,  // amber  on FTURBOTN  2  // tap = toggle normal turbo
  CC,  // cyan   on FMULTIDN  3  // MULTI direct norm: dbltap+hold = turbo & hold>1sec = hold
  CG,  // green  on FHOLD     4  // tap = toggle button hold
  CR,  // red    on FTURBOHA  5  // on hold = alt turbo
  CW,  // white  on FTURBOTA  6  // tap = toggle alt turbo
  CC,  // cyan   on FMULTIDA  7  // MULTI direct alt: dbltap+hold = turbo&& hold>1sec = hold
  CP,  // pink   on F_MODES   8  // number of modes available to cycle through with dbl tap
  CB,  // blue   on FMULTITN  9  // MULTI tap alt : dbltap+hold = turbo & hold>1sec = hold , Btn+Share to toggle
  CA,  // amber  on FMULTITA  10 // MULTI tap norm: dbltap+hold = turbo & hold>1sec = hold , Btn+Share to toggle
};
 
// ++ 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
 
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] ={18       ,18     ,  //  dummy for off state
                  BUTTON_8 ,BUTTON_5//  L2 & R2 default
                  BUTTON_6 ,BUTTON_5//  R3 & R2
                  BUTTON_17,BUTTON_5//  Square & R2
                  };
uint8 QSCfg =0; // quickscope button pair to use 0,2,4,6 (0==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",
};
 
// uint8 number to text translation array
char *NR[]={
  "0",
  "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
  "11", "12", "13", "14", "15", "16", "17", " ",
};
 
// led feedback for configuration menu position
#define LCFGENTER 0
#define LCFGLEAVE 0
uint8 LEDCFG[] = {
  CP, // pink , entering+leaving config mode
};
 
// different text styles for Output Panel messages
#define TXTMENU 0 // menu navigation
#define TXTFEAT 1 // feature & toggle state overview
#define TXTPROT 2 // output protocol
#define TXTLED  3 // led feedback
#define TXTFSEL 4 // feature selection
#define TXTFCUR 5 // show current features name on single tap
//
uint8  TXTLast=100;       // last used text type in output panel
uint16 TXTFEATWait=400;   // time the combo wait before outputting the two-line feature summary text
static char buffer[400]// print buffer
static char *tail;        // print buffer text end pointer
uint8 TXTFCURWait=250;    // time to wait before outputting feature info for single tapped button
uint8 BtnLast=0;          // for indicating last pressed button in fDebugBtnsText
 
 
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
      fDebug();           // debug
    }
  } 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
  }
 
  if (BtnValInfo) fBtnValInfo();
 
  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 bool bIdleLast=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];
    //TextMode(TXTLED,TRUE,"State change");
 
    if (!(bLED[0] + bLED[1] + bLED[2])) { // idle
      bIdle=TRUE;
      ColorLED(LEDF[FNONE]); // pink led
      if (bIdleLast != bIdle) {
        bIdleLast=bIdle;
        TextMode(TXTLED,TRUE,"State: Idle");
      }
    } else { // busy
      bIdle=FALSE;
      LastVal[0]=2; LastVal[1]=2; LastVal[2]=2// reset
      if (bIdleLast != bIdle) {
        bIdleLast=bIdle;
        TextMode(TXTLED,TRUE,"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);
    }
 
    // 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);     
    }
 
    // 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);
    }
 
    // 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]);
        TextMode(TXTMENU,TRUE,"CfgMode 0 : Entered = Main Menu");
      } else {
        ColorLED(LEDCFG[LCFGLEAVE],140,140,3,LEDF[FNONE]);
        TextMode(TXTMENU,TRUE,"CfgMode Exited");
      }
    } // eo: tripple click
  }
}
 
// doing the configuration
void fConfigure() {
    static uint32 lrelease=0;
    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;
        TextMode(TXTMENU,TRUE,CNAMES[CfgMode]);
      }
      if (event_active(BUTTON_13)) {
        CfgMode=CFGTURBO;
        TextMode(TXTMENU,TRUE,CNAMES[CfgMode]);
      }
      if (event_active(BUTTON_11)) {
        CfgMode=CFGSENS_PROT;
        TextMode(TXTMENU,TRUE,CNAMES[CfgMode]);
      }
    } // eo: CfgMode==CFGNONE
 
    else { // ## in sub entry
      if (event_active(BUTTON_3)) {
        CfgMode=CFGNONE; // back to main entry
        TextMode(TXTMENU,TRUE,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)) {
                    if (!TClicked) {
                      if (system_time()> lrelease) DebugBtnFeature(TXTFCUR,BUTTON_2);
                      combo_run(cDebugBtnsText);
                    }
                    TClicked=FALSE;
                    lrelease=system_time()+800;
                  }
                  if (check_active(BUTTON_2,500) && !TClicked) {
                    TClicked=TRUE;
                    BtnLast=BUTTON_2;
                    QSCfg=(QSCfg+2)%8;
                    if (QSCfg==0) bQScope=FALSE; else bQScope=TRUE;
                    DebugBtnFeature(TXTFSEL,BUTTON_2);
                    if (TXTSelect[TXTFEAT]) combo_run(cDebugBtnsText);
                    fBtnValInfo(BUTTON_2);
                  }
                }
          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
      if (event_active(btn) || event_release(btn) || get_actual(btn)) fBtnValInfo(btn);
      fBtnValInfo();
    }
    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) {
  static uint32 TXTFCurBLock=0;
    // cycle through modes with dbl tap
    if (fTaps(btn,2,250)) {
 
      TXTFCurBLock=system_time()+TXTFCURWait; // block current button text info when new is selected
      combo_stop(cDebugBtnText);
 
      BtnsFeature[btn]=(BtnsFeature[btn]+1)%F_MODES;
      BtnsToggle[btn]=TOFF; // toggle state reset
      DebugBtnFeature(TXTFSEL,btn);
      //if (cDebugBtnText)
      if (BtnsFeature[btn] < F_MODES ) { // led toggle feedback
        if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(LEDF[BtnsFeature[btn]],200,200,2,LEDF[FNONE]);
      }
    } else if (event_active(btn)) {
      if (TXTSelect[TXTFCUR] && system_time() > TXTFCurBLock) {
        combo_run(cDebugBtnText);
      }
    }
 
    // update debug info for current button
    if (event_active(btn)) {
      BtnLast=btn;
      if (TXTSelect[TXTFEAT]) combo_run(cDebugBtnsText);
    }
}
 
// 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) {
    BtnsToggle[btn]=0;
    if (get_actual(btn)) { BtnsToggle[btn]=1; bLED[idx_LEDFTN]=1; set_val(btn,BtnTurboVal[TurboIdxN]); }
  }
  if (BtnsFeature[btn]==FTURBOHA) {
    BtnsToggle[btn]=0;
   if (get_actual(btn)) { BtnsToggle[btn]=1; bLED[idx_LEDFTA]=1; set_val(btn,BtnTurboVal[TurboIdxA]); }
  }
 
  if (BtnValInfo) if (event_release(btn)||event_active(btn)||get_actual(btn)) fBtnValInfo(btn);
}
 
// 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
    }
    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
    }
    // 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;
        if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(LEDF[BtnsFeature[btn]],140,140,3,LEDF[FNONE]);
      }
      else if (BtnsFeature[btn]==FMULTITN) {
        BtnsFeature[btn]=FMULTIDN; BtnsToggle[btn]=TOFF;
        if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(LEDF[BtnsFeature[btn]],140,140,3,LEDF[FNONE]);
      }
      else if (BtnsFeature[btn]==FMULTIDA) {
        BtnsFeature[btn]=FMULTITA; BtnsToggle[btn]=TOFF;
        if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(LEDF[BtnsFeature[btn]],140,140,3,LEDF[FNONE]);
      }
      else if (BtnsFeature[btn]==FMULTITA) {
        BtnsFeature[btn]=FMULTIDA; BtnsToggle[btn]=TOFF;
        if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(LEDF[BtnsFeature[btn]],140,140,3,LEDF[FNONE]);
      }
  }
}
 
// turbo<->altturbo
void fTurboModeFlip(uint8 btn) {
  bool flipped=FALSE;
  if      (BtnsFeature[btn]==FTURBOHN) { BtnsFeature[btn]=FTURBOHA; flipped=TRUE; } // hold
  else if (BtnsFeature[btn]==FTURBOHA) { BtnsFeature[btn]=FTURBOHN; flipped=TRUE; }
  else if (BtnsFeature[btn]==FTURBOTN) { BtnsFeature[btn]=FTURBOTA; flipped=TRUE; } // toggle
  else if (BtnsFeature[btn]==FTURBOTA) { BtnsFeature[btn]=FTURBOTN; flipped=TRUE; }
  else if (BtnsFeature[btn]==FMULTIDN) { BtnsFeature[btn]=FMULTIDA; flipped=TRUE; } // multi direct
  else if (BtnsFeature[btn]==FMULTIDA) { BtnsFeature[btn]=FMULTIDN; flipped=TRUE; }
  else if (BtnsFeature[btn]==FMULTITN) { BtnsFeature[btn]=FMULTITA; flipped=TRUE; } // multi toggle
  else if (BtnsFeature[btn]==FMULTITA) { BtnsFeature[btn]=FMULTITN; flipped=TRUE; }
 
  if (flipped) {
    DebugBtnFeature(TXTFSEL,btn);
    if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(LEDF[BtnsFeature[btn]],140,140,3,LEDF[FNONE]);
  }
}
 
 
// 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) {
 
    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);
            TextMode(TXTPROT,TRUE,"PROTOCOL_PS3");
            break;
        case PIO_XB360:
            port_connect(PORT_USB_C, PROTOCOL_XB360);
            TextMode(TXTPROT,TRUE,"PROTOCOL_XB360");
            break;
        case PIO_PS4:
            port_connect(PORT_USB_C, PROTOCOL_PS4);
            TextMode(TXTPROT,TRUE,"PROTOCOL_PS4");
            break;
        case PIO_XB1:
            port_connect(PORT_USB_C, PROTOCOL_XB1);
            TextMode(TXTPROT,TRUE,"PROTOCOL_XB1");
            break;
        case PIO_SWITCH:
            port_connect(PORT_USB_C, PROTOCOL_SWITCH);
            TextMode(TXTPROT,TRUE,"PROTOCOL_SWITCH");
            break;
        default:
            port_connect(PORT_USB_C, PROTOCOL_AUTO);
            TextMode(TXTPROT,TRUE,"PROTOCOL_AUTO");
    }
    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() {
  if (elapsed_time()) {
    fNullOutput()// zero all output via set_val 
    set_val(ACCEL_1_Z, TPress / 10);
    set_val(ACCEL_2_X, TRelease / 10);
    set_val(ACCEL_2_Z, CfgMode);
    if (CfgMode==CFGBTN_SCOPE) fBtnValInfo();
  }
}
 
 
// last button pressed info
void fBtnValInfo(uint8 btn) {
  // output format BtnNr NN*1000 , Feature FF , Toggle TT/100
  static fix32 DebugLastBtn=9999.0;
 
  if (btn>0) {
    // device monitor value
    DebugLastBtn=(fix32)btn+1.0; // nr 16 -> name_17.0
    DebugLastBtn*=1000.0; // button name 17: 17000.00
    if (btn!=BUTTON_2) {
      DebugLastBtn+=(fix32)BtnsFeature[btn]; // feature 170FF.00
      DebugLastBtn+=(fix32)BtnsToggle[btn]/100.0; // feature 170FF.00
    } else {
      DebugLastBtn+=(fix32)bQScope;
      DebugLastBtn+=(fix32)QSCfg/100f;
    }
  }
 
  if (DebugLastBtn!=9999.0) { // output
    set_val(BtnValTo, DebugLastBtn);
  }
}
 
combo cDebugBtnsText { // all buttons features & states
  wait(TXTFEATWait);
  fDebugBtnsText();
  wait(0);
}
 
void fDebugBtnsText() {
  uint8 btn;
  TextMode(TXTFEAT,FALSE,"<h3><pre><b>");
  for (btn=BUTTON_4;btn<BUTTON_10;btn++)
      TextMode(-1,FALSE,"  ",NR[btn+1]," |");
  for (btn=BUTTON_10;btn<=BUTTON_17;btn++)
      TextMode(-1,FALSE," ",NR[btn+1]," |");
  print(" QS</b><br>");
  for (btn=BUTTON_4;btn<=BUTTON_17;btn++) {
    if (BtnsFeature[btn]<10) TextMode(-1,FALSE," ",NR[BtnsFeature[btn]],".",NR[BtnsToggle[btn]],"|");
    else TextMode(-1,FALSE," ",NR[BtnsFeature[btn]],".",NR[BtnsToggle[btn]],"|");
  }
  TextMode(-1,FALSE," ",NR[QSCfg/2],".",NR[bQScope]);
  print("<br><font color='green'>");
  // feature selected indicator
  for (btn=BUTTON_4;btn<=BUTTON_17;btn++) {
    if (BtnLast==btn && BtnsFeature[btn]) print("  +  ");
    else if (BtnsFeature[btn]) print("  ^  ");
    else print("     ");
  }
  if (bQScope && BtnLast==BUTTON_2) print("  +");
  else if (bQScope) print("  ^");
  else print("");
  print("</font></pre></h3>");
  print(NULL);
}
 
void DebugBtnFeature(uint8 txtmode,uint8 btn) {
  char *symbl[] = {" -> ", " == "};
  uint8 isymbl=0;
  if (txtmode!=TXTFSEL) isymbl=1;
  if (btn!=BUTTON_2) {
    TextMode(txtmode,TRUE,"Btn_",NR[btn+1],symbl[isymbl],
        FNAMES[BtnsFeature[btn]]);
  } else {
    if (bQScope) TextMode(txtmode,TRUE,"Quickscope activate, Scope Btn_",NR[QSBtns[QSCfg]+1],
                  " , Fire Btn_",NR[QSBtns[QSCfg+1]+1]);
    else TextMode(txtmode,TRUE,"Quickscope disabled");
  }
}
 
combo cDebugBtnText{
  wait(TXTFCURWait);
  DebugBtnFeature(TXTFCUR,BtnLast);
  wait(0);
}
 
// text styles
void TextMode(int8 tag, bool write,
  char *str1,  char *str2, char *str3, char *str4,
  char *str5,  char *str6, char *str7, char *str8) {
 
  if (tag>-1) {
    if (TXTLast!=tag) TXTLast=tag;
    if (!TXTSelect[tag]) return; // skip disabled debug types
 
    switch(tag) {
      case TXTMENU: print("<b><font color='#00802b'>MENU</font></b> ");
      break;
      case TXTFEAT: print("<b><font color='#00802b'>FEATURES</font></b> ");
      break;
      case TXTPROT: print("<b><font color='#00802b'>PROTOCOL</font></b> ");
      break;
      case TXTLED:  print("<b><font color='#00802b'>LED</font></b> ");
      break;
      case TXTFSEL: print("<b><font color='#00802b'>SELECTED</font></b> ");
      break;
      case TXTFCUR: print("<b><font color='#00802b'>CURRENT</font></b> ");
      break;
    }
  }
 
  if (str1)   print(str1);
  if (str2)   print(str2);
  if (str3)   print(str3);
  if (str4)   print(str4);
  if (str5)   print(str5);
  if (str6)   print(str6);
  if (str7)   print(str7);
  if (str8)   print(str8);
  if (write)  print(NULL);
}
 
// J2Kbr print to output panel without automatic linebreak
void print(char *str, bool reset) {
  if (!TXTSelect[TXTLast]) return; // skip disabled debug types
  if (reset) {
    tail = NULL;
    memset(&buffer,0,sizeof(buffer));
    return;
  }
 
  if(str) {
    if(!tail) {
      tail = &buffer;     // new text
    }
    while(*str) {
      *tail++ = *str++; // append string
    }
  } else if(tail) {
    printf(&buffer);
    tail = NULL;
    memset(&buffer,0,sizeof(buffer));
  }
}
 
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 » Wed Feb 13, 2019 2:58 pm

The script works really well, though the output protocol still doesn't change when pressing share in the appropriate config mode.

Also, if it's not to much trouble, would it be possible to have the text-based feature status summary show upon entering the button feature config mode as well?

Edit:
I figured out why the output protocol changer wasn't working.

You accidentally left this in.
Code: Select all
if(bConfigure) return;

I commented it out and now the script works just fine.
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 » Wed Feb 13, 2019 4:52 pm

Thank you..removed the line in protocol change and added the summary on entering CFGBTN_SCOPE mode:

Code: Select all
#pragma METAINFO("Fenria Special", 0, 71, "")
 
//  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: 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 via the Output Panel
//
//   +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
 
// DEBUG settings
//
bool TXTSelect[]={ // enable/disable output panel text messages per type
        TRUE//  TXTMENU   // menu navigation
        TRUE , //  TXTFEAT   // two-line feature status summary output
        TRUE//  TXTPROT   // output protocol
        FALSE, //  TXTLED    // led feedback
        TRUE//  TXTFSEL   // button feature selection
        TRUE//  TXTFCUR   // show current features name on a single press
};
#define BtnValInfo  TRUE      // show feature and toggle state in Device Monitor
#define BtnValTo    BUTTON_21 // <-     at this position        --^
 
#define _ColorBrightness
#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: USED INTERNALY",
  "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     0  // no special function
  CB,  // blue   on FTURBOHN  1  // on hold = normal turbo
  CA,  // amber  on FTURBOTN  2  // tap = toggle normal turbo
  CC,  // cyan   on FMULTIDN  3  // MULTI direct norm: dbltap+hold = turbo & hold>1sec = hold
  CG,  // green  on FHOLD     4  // tap = toggle button hold
  CR,  // red    on FTURBOHA  5  // on hold = alt turbo
  CW,  // white  on FTURBOTA  6  // tap = toggle alt turbo
  CC,  // cyan   on FMULTIDA  7  // MULTI direct alt: dbltap+hold = turbo&& hold>1sec = hold
  CP,  // pink   on F_MODES   8  // number of modes available to cycle through with dbl tap
  CB,  // blue   on FMULTITN  9  // MULTI tap alt : dbltap+hold = turbo & hold>1sec = hold , Btn+Share to toggle
  CA,  // amber  on FMULTITA  10 // MULTI tap norm: dbltap+hold = turbo & hold>1sec = hold , Btn+Share to toggle
};
 
// ++ 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
 
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] ={18       ,18     ,  //  dummy for off state
                  BUTTON_8 ,BUTTON_5//  L2 & R2 default
                  BUTTON_6 ,BUTTON_5//  R3 & R2
                  BUTTON_17,BUTTON_5//  Square & R2
                  };
uint8 QSCfg =0; // quickscope button pair to use 0,2,4,6 (0==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",
};
 
// uint8 number to text translation array
char *NR[]={
  "0",
  "1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
  "11", "12", "13", "14", "15", "16", "17", " ",
};
 
// led feedback for configuration menu position
#define LCFGENTER 0
#define LCFGLEAVE 0
uint8 LEDCFG[] = {
  CP, // pink , entering+leaving config mode
};
 
// different text styles for Output Panel messages
#define TXTMENU 0 // menu navigation
#define TXTFEAT 1 // feature & toggle state overview
#define TXTPROT 2 // output protocol
#define TXTLED  3 // led feedback
#define TXTFSEL 4 // feature selection
#define TXTFCUR 5 // show current features name on single tap
//
uint8  TXTLast=100;       // last used text type in output panel
uint16 TXTFEATWait=400;   // time the combo wait before outputting the two-line feature summary text
static char buffer[400]// print buffer
static char *tail;        // print buffer text end pointer
uint8 TXTFCURWait=250;    // time to wait before outputting feature info for single tapped button
uint8 BtnLast=0;          // for indicating last pressed button in fDebugBtnsText
 
 
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
      fDebug();           // debug
    }
  } 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
  }
 
  if (BtnValInfo) fBtnValInfo();
 
  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 bool bIdleLast=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];
    //TextMode(TXTLED,TRUE,"State change");
 
    if (!(bLED[0] + bLED[1] + bLED[2])) { // idle
      bIdle=TRUE;
      ColorLED(LEDF[FNONE]); // pink led
      if (bIdleLast != bIdle) {
        bIdleLast=bIdle;
        TextMode(TXTLED,TRUE,"State: Idle");
      }
    } else { // busy
      bIdle=FALSE;
      LastVal[0]=2; LastVal[1]=2; LastVal[2]=2// reset
      if (bIdleLast != bIdle) {
        bIdleLast=bIdle;
        TextMode(TXTLED,TRUE,"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);
    }
 
    // 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);     
    }
 
    // 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);
    }
 
    // 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]);
        TextMode(TXTMENU,TRUE,"CfgMode 0 : Entered = Main Menu");
      } else {
        ColorLED(LEDCFG[LCFGLEAVE],140,140,3,LEDF[FNONE]);
        TextMode(TXTMENU,TRUE,"CfgMode Exited");
        combo_stop(cDebugBtnsText);
      }
    } // eo: tripple click
  }
}
 
// doing the configuration
void fConfigure() {
    static uint32 lrelease=0;
    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;
        TextMode(TXTMENU,TRUE,CNAMES[CfgMode]);
        combo_run(cDebugBtnsText);
      }
      if (event_active(BUTTON_13)) {
        CfgMode=CFGTURBO;
        TextMode(TXTMENU,TRUE,CNAMES[CfgMode]);
      }
      if (event_active(BUTTON_11)) {
        CfgMode=CFGSENS_PROT;
        TextMode(TXTMENU,TRUE,CNAMES[CfgMode]);
      }
    } // eo: CfgMode==CFGNONE
 
    else { // ## in sub entry
      if (event_active(BUTTON_3)) {
        CfgMode=CFGNONE; // back to main entry
        TextMode(TXTMENU,TRUE,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)) {
                    if (!TClicked) {
                      if (system_time()> lrelease) DebugBtnFeature(TXTFCUR,BUTTON_2);
                      combo_run(cDebugBtnsText);
                    }
                    TClicked=FALSE;
                    lrelease=system_time()+800;
                  }
                  if (check_active(BUTTON_2,500) && !TClicked) {
                    TClicked=TRUE;
                    BtnLast=BUTTON_2;
                    QSCfg=(QSCfg+2)%8;
                    if (QSCfg==0) bQScope=FALSE; else bQScope=TRUE;
                    DebugBtnFeature(TXTFSEL,BUTTON_2);
                    combo_run(cDebugBtnsText);
                    fBtnValInfo(BUTTON_2);
                  }
                }
          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
      if (event_active(btn) || event_release(btn) || get_actual(btn)) fBtnValInfo(btn);
      fBtnValInfo();
    }
    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) {
  static uint32 TXTFCurBLock=0;
    // cycle through modes with dbl tap
    if (fTaps(btn,2,250)) {
 
      TXTFCurBLock=system_time()+TXTFCURWait; // block current button text info when new is selected
      combo_stop(cDebugBtnText);
 
      BtnsFeature[btn]=(BtnsFeature[btn]+1)%F_MODES;
      BtnsToggle[btn]=TOFF; // toggle state reset
      DebugBtnFeature(TXTFSEL,btn);
      //if (cDebugBtnText)
      if (BtnsFeature[btn] < F_MODES ) { // led toggle feedback
        if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(LEDF[BtnsFeature[btn]],200,200,2,LEDF[FNONE]);
      }
    } else if (event_active(btn)) {
      if (TXTSelect[TXTFCUR] && system_time() > TXTFCurBLock) {
        combo_run(cDebugBtnText);
      }
    }
 
    // update debug info for current button
    if (event_active(btn)) {
      BtnLast=btn;
      combo_run(cDebugBtnsText);
    }
}
 
// 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) {
    BtnsToggle[btn]=0;
    if (get_actual(btn)) { BtnsToggle[btn]=1; bLED[idx_LEDFTN]=1; set_val(btn,BtnTurboVal[TurboIdxN]); }
  }
  if (BtnsFeature[btn]==FTURBOHA) {
    BtnsToggle[btn]=0;
   if (get_actual(btn)) { BtnsToggle[btn]=1; bLED[idx_LEDFTA]=1; set_val(btn,BtnTurboVal[TurboIdxA]); }
  }
 
  if (BtnValInfo) if (event_release(btn)||event_active(btn)||get_actual(btn)) fBtnValInfo(btn);
}
 
// 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
    }
    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
    }
    // 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;
        if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(LEDF[BtnsFeature[btn]],140,140,3,LEDF[FNONE]);
      }
      else if (BtnsFeature[btn]==FMULTITN) {
        BtnsFeature[btn]=FMULTIDN; BtnsToggle[btn]=TOFF;
        if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(LEDF[BtnsFeature[btn]],140,140,3,LEDF[FNONE]);
      }
      else if (BtnsFeature[btn]==FMULTIDA) {
        BtnsFeature[btn]=FMULTITA; BtnsToggle[btn]=TOFF;
        if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(LEDF[BtnsFeature[btn]],140,140,3,LEDF[FNONE]);
      }
      else if (BtnsFeature[btn]==FMULTITA) {
        BtnsFeature[btn]=FMULTIDA; BtnsToggle[btn]=TOFF;
        if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(LEDF[BtnsFeature[btn]],140,140,3,LEDF[FNONE]);
      }
  }
}
 
// turbo<->altturbo
void fTurboModeFlip(uint8 btn) {
  bool flipped=FALSE;
  if      (BtnsFeature[btn]==FTURBOHN) { BtnsFeature[btn]=FTURBOHA; flipped=TRUE; } // hold
  else if (BtnsFeature[btn]==FTURBOHA) { BtnsFeature[btn]=FTURBOHN; flipped=TRUE; }
  else if (BtnsFeature[btn]==FTURBOTN) { BtnsFeature[btn]=FTURBOTA; flipped=TRUE; } // toggle
  else if (BtnsFeature[btn]==FTURBOTA) { BtnsFeature[btn]=FTURBOTN; flipped=TRUE; }
  else if (BtnsFeature[btn]==FMULTIDN) { BtnsFeature[btn]=FMULTIDA; flipped=TRUE; } // multi direct
  else if (BtnsFeature[btn]==FMULTIDA) { BtnsFeature[btn]=FMULTIDN; flipped=TRUE; }
  else if (BtnsFeature[btn]==FMULTITN) { BtnsFeature[btn]=FMULTITA; flipped=TRUE; } // multi toggle
  else if (BtnsFeature[btn]==FMULTITA) { BtnsFeature[btn]=FMULTITN; flipped=TRUE; }
 
  if (flipped) {
    DebugBtnFeature(TXTFSEL,btn);
    if (BtnsFeature[btn] < sizeof(LEDF)) ColorLED(LEDF[BtnsFeature[btn]],140,140,3,LEDF[FNONE]);
  }
}
 
 
// 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);
            TextMode(TXTPROT,TRUE,"PROTOCOL_PS3");
            break;
        case PIO_XB360:
            port_connect(PORT_USB_C, PROTOCOL_XB360);
            TextMode(TXTPROT,TRUE,"PROTOCOL_XB360");
            break;
        case PIO_PS4:
            port_connect(PORT_USB_C, PROTOCOL_PS4);
            TextMode(TXTPROT,TRUE,"PROTOCOL_PS4");
            break;
        case PIO_XB1:
            port_connect(PORT_USB_C, PROTOCOL_XB1);
            TextMode(TXTPROT,TRUE,"PROTOCOL_XB1");
            break;
        case PIO_SWITCH:
            port_connect(PORT_USB_C, PROTOCOL_SWITCH);
            TextMode(TXTPROT,TRUE,"PROTOCOL_SWITCH");
            break;
        default:
            port_connect(PORT_USB_C, PROTOCOL_AUTO);
            TextMode(TXTPROT,TRUE,"PROTOCOL_AUTO");
    }
    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() {
  if (elapsed_time()) {
    fNullOutput()// zero all output via set_val 
    set_val(ACCEL_1_Z, TPress / 10);
    set_val(ACCEL_2_X, TRelease / 10);
    set_val(ACCEL_2_Z, CfgMode);
    if (CfgMode==CFGBTN_SCOPE) fBtnValInfo();
  }
}
 
 
// last button pressed info
void fBtnValInfo(uint8 btn) {
  // output format BtnNr NN*1000 , Feature FF , Toggle TT/100
  static fix32 DebugLastBtn=9999.0;
 
  if (btn>0) {
    // device monitor value
    DebugLastBtn=(fix32)btn+1.0; // nr 16 -> name_17.0
    DebugLastBtn*=1000.0; // button name 17: 17000.00
    if (btn!=BUTTON_2) {
      DebugLastBtn+=(fix32)BtnsFeature[btn]; // feature 170FF.00
      DebugLastBtn+=(fix32)BtnsToggle[btn]/100.0; // feature 170FF.00
    } else {
      DebugLastBtn+=(fix32)bQScope;
      DebugLastBtn+=(fix32)QSCfg/100f;
    }
  }
 
  if (DebugLastBtn!=9999.0) { // output
    set_val(BtnValTo, DebugLastBtn);
  }
}
 
combo cDebugBtnsText { // all buttons features & states
  wait(TXTFEATWait);
  fDebugBtnsText();
  wait(0);
}
 
void fDebugBtnsText() {
  uint8 btn;
  TextMode(TXTFEAT,FALSE,"<h3><pre><b>");
  for (btn=BUTTON_4;btn<BUTTON_10;btn++)
      TextMode(-1,FALSE,"  ",NR[btn+1]," |");
  for (btn=BUTTON_10;btn<=BUTTON_17;btn++)
      TextMode(-1,FALSE," ",NR[btn+1]," |");
  print(" QS</b><br>");
  for (btn=BUTTON_4;btn<=BUTTON_17;btn++) {
    if (BtnsFeature[btn]<10) TextMode(-1,FALSE," ",NR[BtnsFeature[btn]],".",NR[BtnsToggle[btn]],"|");
    else TextMode(-1,FALSE," ",NR[BtnsFeature[btn]],".",NR[BtnsToggle[btn]],"|");
  }
  TextMode(-1,FALSE," ",NR[QSCfg/2],".",NR[bQScope]);
  print("<br><font color='green'>");
  // feature selected indicator
  for (btn=BUTTON_4;btn<=BUTTON_17;btn++) {
    if (BtnLast==btn && BtnsFeature[btn]) print("  +  ");
    else if (BtnsFeature[btn]) print("  ^  ");
    else print("     ");
  }
  if (bQScope && BtnLast==BUTTON_2) print("  +");
  else if (bQScope) print("  ^");
  else print("");
  print("</font></pre></h3>");
  print(NULL);
}
 
void DebugBtnFeature(uint8 txtmode,uint8 btn) {
  char *symbl[] = {" -> ", " == "};
  uint8 isymbl=0;
  if (txtmode!=TXTFSEL) isymbl=1;
  if (btn!=BUTTON_2) {
    TextMode(txtmode,TRUE,"Btn_",NR[btn+1],symbl[isymbl],
        FNAMES[BtnsFeature[btn]]);
  } else {
    if (bQScope) TextMode(txtmode,TRUE,"Quickscope activate, Scope Btn_",NR[QSBtns[QSCfg]+1],
                  " , Fire Btn_",NR[QSBtns[QSCfg+1]+1]);
    else TextMode(txtmode,TRUE,"Quickscope disabled");
  }
}
 
combo cDebugBtnText{
  wait(TXTFCURWait);
  DebugBtnFeature(TXTFCUR,BtnLast);
  wait(0);
}
 
// text styles
void TextMode(int8 tag, bool write,
  char *str1,  char *str2, char *str3, char *str4,
  char *str5,  char *str6, char *str7, char *str8) {
 
  if (tag>-1) {
    if (TXTLast!=tag) TXTLast=tag;
    if (!TXTSelect[tag]) return; // skip disabled debug types
 
    switch(tag) {
      case TXTMENU: print("<b><font color='#00802b'>MENU</font></b> ");
      break;
      case TXTFEAT: print("<b><font color='#00802b'>FEATURES</font></b> ");
      break;
      case TXTPROT: print("<b><font color='#00802b'>PROTOCOL</font></b> ");
      break;
      case TXTLED:  print("<b><font color='#00802b'>LED</font></b> ");
      break;
      case TXTFSEL: print("<b><font color='#00802b'>SELECTED</font></b> ");
      break;
      case TXTFCUR: print("<b><font color='#00802b'>CURRENT</font></b> ");
      break;
    }
  }
 
  if (str1)   print(str1);
  if (str2)   print(str2);
  if (str3)   print(str3);
  if (str4)   print(str4);
  if (str5)   print(str5);
  if (str6)   print(str6);
  if (str7)   print(str7);
  if (str8)   print(str8);
  if (write)  print(NULL);
}
 
// J2Kbr print to output panel without automatic linebreak
void print(char *str, bool reset) {
  if (!TXTSelect[TXTLast]) return; // skip disabled debug types
  if (reset) {
    tail = NULL;
    memset(&buffer,0,sizeof(buffer));
    return;
  }
 
  if(str) {
    if(!tail) {
      tail = &buffer;     // new text
    }
    while(*str) {
      *tail++ = *str++; // append string
    }
  } else if(tail) {
    printf(&buffer);
    tail = NULL;
    memset(&buffer,0,sizeof(buffer));
  }
}
 
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 » Wed Feb 13, 2019 6:40 pm

The script works perfectly from what I can tell based on the testing I've done.

Thank you very much for all your help Scachi, and for basically completely rewriting the script, as well as adding in some new stuff that wasn't in the original script.

I really really appreciate it.
User avatar
Fenria
Command Sergeant Major
Command Sergeant Major
 
Posts: 147
Joined: Thu May 21, 2015 5:56 pm

Previous

Return to GPC2 Script Programming

Who is online

Users browsing this forum: No registered users and 50 guests