/* * `.:/++` ....`` * `/ossss: `.` `--------.` * /ssso. .----..```..----------- `` * -ss+``-----------------------. ssss -/++/` /ss- ./++/- //+// oss `oss- * `os+ `----------------.......--` sssss: `s400s. +sH- -sBsss` :ssBCs sVs /++` * `` .:ss+ `-------..``````````````````` sso+ss` +so/ss. -:::::. +se- `--- `-::::. `-:`.::. .::::- -su/ss+ `ss:sss `-::::-` s5s .--. --- .-- -:::- .::::---. * .oso+++oossso``---..`` ``..----------.....--. sso.ss/ -ss-/ss. :so++sss+ +sn- .oso- /ss+/+ss/ -ss+sss++ss+/+o- -sr:/ss- +ss`sss ooo+osss- sCs :ss+` oss. ossooosss+ `oso//osso/ * -ssssssssssss.`--.` `.----------------. sso /ss. os+ /ss. `.----sss` +sn+/ss+` :Dr+-.-+ss.-sss-```sss/-.` -sn:`oso .ss: sss `.---/ss+ sss:+ss: oss. oss:```sss`:ss: .ss+ * .ssssssssssss+ .. `.--------------. sso `os+-ss. /ss. /sso++sss` +siooss: +sso+++ooo`-ss+ ./+osso: -sa: -ss-+so sss `+ss++oss+ s6s+sss. oss. oss. sss``oss++oso. * :+ossssssssss: ` `------------..` sso -ssos/ /ss. .sss.`.sss-` +sn:`+ss/`-sso-.`..- -ss+ `.```:sso -sb: +soss. sss /ss+``:sso.`sBs`-sss- oss. oss. sss``oso:::.` * `-+ssssssss. .--------` ss+ +sso` /ss. +3999++sss: /sg- `/ss+.-+sssooo+ .ss+ .osoosso- -sy: `sss/ oso .ossoo+osso.s9s .+ss/ oss` +ss. oss`.sssoooo+:` * `+sssssss. ` .------` ``` ```` ``` `...` ... ``` ```` `....` ``` `....`` ``` ``` ``` `...` `..` ``` ``` ``` ``` ``` +ss---:/sso * -sssssss: .. `----. `sss:-.-:ss+ * `:ossssso .-. .---- ./+oooo++-` * `..``-+ssss: `---` .----` `.-::::-` .//- ```` * `..-----.`.:+ss: `----- `------..` `:osssoooo/ /ss: * `----------.`.-/:` .------` .------. `+ss+-`````. /ss:``..` ``...` ``` `...` ``..```` `...` * `------------....` `.-------. `-----. /sso /ss/ossso/ /osssso+. +o+/ossso- `/oooooooo/ -+ooooo+` * `--.....---------...``` ```` `.---------. `...-. oss/ /sso-.-sss- :----+ss+ oss+-.:s1s :ss:``:ss/.:ss/..-sso * `.------------------..```.--------.` ` +ss+ /ss: +ss- -+o++osso oss. `s9s -ss+--/ss: ssso+++sss * `.--------------.```.----------` .sss/.` `` /ss: +ss-:ss+..:sso oss. s8s `+ssooo/- oss/-..... * `---------..````.------------. .ossso+++o+ /ss: +ss--sso//+sss+-oss. s4s -sso/:::-` .oss+///+: * .----..``````......----------- .://+//:` .::. .::` .://:.-//:`-::` ::: :ss+++ooss: `-:////-` * .`````....` ``--------.` `sso````.sso * ``..-. `-...`` /ossoooss+. * `..--..` * * * +++ .+++: /++++++++/:. .:/+++++/: .+++/` .+++/ ++++. ++++. `-/++++++/: * oooo .ooo: +ooo:--:+ooo/ :ooo/:::/+/ -ooo+` .ooo+` ooooo: .o-o` `/ooo+//://+: * oooo .ooo: +ooo` :ooo- oooo` ` .ooo+` .ooo+` oooooo/` .o-o` .oooo-` * oooo .ooo: +ooo` -ooo- -ooo+:.` .ooo+.ooo/` ooo:/oo+. .o-o` +ooo. * oooo .ooo: +ooo.`..:ooo+` `:+oooo+:` `+ooooo/ ooo: :ooo- .o-o` oooo * oooo .ooo: +ooooooooo+:` `-:oooo- `+ooo/ ooo/ .+oo/.o-o` +ooo. * oooo .ooo: +ooo-...`` `oooo /ooo. ooo/ `/oo-o-o` .oooo- * oooo::::::. .ooo: +ooo` :o//:::+ooo: /ooo. ooo/ .o-o-o` ./oooo/:::/+/ * +ooooooooo: .ooo: /ooo` -/++ooo+/:. :ooo. ooo: `.o.+ `-/+oooo+/- * * An open-source mouth operated sip and puff joystick that enables people with limited hand function to emulate a mouse on their computer and/or smartphone. */ /* * Copyright (c) Neil Squire Society * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ //TITLE: LipSync_Gaming_Firmware //AUTHOR: MakersMakingChange //VERSION: 3.0 (27 Jun 2022) //Copyright Neil Squire Society 2016-2022. #include #include "Joystick.h" //***OUTPUT ACTIONS***// - DO NOT CHANGE // These are the different actions the LipSync can perform based on different sip and puff inputs. #define OUTPUT_NOTHING (int)0 // No action #define OUTPUT_BUTTON_ONE (int)1 // Press and release button one or button X1(Left USB)/View(Right USB) in XAC #define OUTPUT_BUTTON_TWO (int)2 // Press and release button two or button X2(Left USB)/Menu(Right USB) in XAC #define OUTPUT_BUTTON_THREE (int)3 // Press and release button three or button LS(Left USB)/RS(Right USB) in XAC #define OUTPUT_BUTTON_FOUR (int)4 // Press and release button four or button LB(Left USB)/RB(Right USB) in XAC #define OUTPUT_BUTTON_FIVE (int)5 // Press and release button five or button A(Left USB)/X(Right USB) in XAC #define OUTPUT_BUTTON_SIX (int)6 // Press and release button six button B(Left USB)/Y(Right USB) in XAC #define OUTPUT_JOYSTICK_HOME_RESET (int)7 // Initiates the Joystick home reset routine to reset center position. #define OUTPUT_JOYSTICK_CALIBRATION (int)8 // Initiates the Joystick calibration to calibrate joystick range and reset center position. //***OUTPUT MAPPING***// - CUSTOMIZABLE //These values can be changed to remap different output actions to different input actions #define ACTION_SHORT_PUFF OUTPUT_BUTTON_ONE // Default: Press and release button one or button X1(Left USB)/View(Right USB) in XAC #define ACTION_SHORT_SIP OUTPUT_BUTTON_TWO // Default: Press and release button two or button X2(Left USB)/Menu(Right USB) in XAC #define ACTION_LONG_PUFF OUTPUT_BUTTON_FIVE // Default: Press and release button five or button A(Left USB)/X(Right USB) in XAC #define ACTION_LONG_SIP OUTPUT_BUTTON_SIX // Default: Press and release button six or button B(Left USB)/Y(Right USB) in XAC #define ACTION_VLONG_PUFF OUTPUT_JOYSTICK_HOME_RESET // Default: Initiates the Joystick home reset routine to reset center position. #define ACTION_VLONG_SIP OUTPUT_NOTHING // Default: No action //***CUSTOMIZABLE VARIABLES***// #define ROTATION_ANGLE 0 // CCW Rotation angle between Screen "up" to LipSync "up" {0,90,180,270} [degrees] #define PUFF_PRESSURE_THRESHOLD_DEFAULT (byte)10 // Pressure sip and puff threshold [percentage] #define SIP_PRESSURE_THRESHOLD_DEFAULT (byte)10 // Pressure sip and puff threshold [percentage] #define PUFF_COUNT_THRESHOLD_MED 150 // Threshold between short and medium puff input [cycle counts] #define PUFF_COUNT_THRESHOLD_LONG 750 // Threshold between medium and long puff [cycle counts] #define SIP_COUNT_THRESHOLD_MED 150 // Threshold between short and medium puff input [cycle counts] #define SIP_COUNT_THRESHOLD_LONG 750 // Threshold between medium and long puff in [cycle counts] #define SENSITIVITY_COUNTER (byte)5 // Default sensitivity level #define JOYSTICK_DELAY 5 // Current joystick delay [ms] #define DEBUG_MODE_DELAY (int)150 // The delay used in debug mode between each reading [ms] #define SERIAL_DELAY (byte)5 // The delay after a serial write [ms] #define EEPROM_WRITE_DELAY (byte)10 // The delay after an EEPROM write [ms] #define PRESSURE_HANDLER_DELAY (byte)5 // The delay added between pressure read cycles [ms] #define JOYSTICK_BUTTON_DELAY 150 // The delay after a joystick button press before release #define BUTTON_LONG_PRESS_TIME 2000 // The time required to press a button to change button mode #define BUTTON_DIGITAL_MODE 1 // The digital button mode #define BUTTON_ANALOG_MODE 2 // The analog button mode //*** DRIFT REDUCTIONS ***// CHANGE WITH CAUTION #define JOYSTICK_DEADBAND 30 // Joystick deadband {ADC steps] #define CHANGE_DEFAULT_TOLERANCE 3 // The tolerance in changes between current reading and previous reading [ADC steps] //***DON'T CHANGE THESE CONSTANTS***// #define LIPSYNC_MODEL (byte)2 // LipSync Gaming #define LIPSYNC_VERSION (byte)30 // LipSync Version #define SIP_PRESSURE_THRESHOLD_MIN (byte)10 // Minimum Pressure sip and puff threshold [percentage] #define SIP_PRESSURE_THRESHOLD_MAX (byte)50 // Maximum Pressure sip and puff threshold [percentage] #define PUFF_PRESSURE_THRESHOLD_MIN (byte)10 // Minimum Pressure sip and puff threshold [percentage] #define PUFF_PRESSURE_THRESHOLD_MAX (byte)50 // Maximum Pressure sip and puff threshold [percentage] #define INPUT_ACTION_COUNT 6 // Number of available sip and puff input types #define JOYSTICK_LIFT_THRESOLD 400 // Opposite FSR value nearing liftoff during purposeful movement [ADC steps] #define JOYSTICK_MAX_DEADZONE 250 // Joystick maximum allowed deadzone {ADC steps] #define BUTTON_MODE BUTTON_DIGITAL_MODE // Set button mode ( 1 = Digital button mode , 2 = Analog button mode ) #define JS_MAPPED_IN_DEADZONE 0.50 // The deadzone value of mapped joystick values #define JS_MAPPED_IN_NEUTRAL 12 // Mapped neutral joystick value #define JS_MAPPED_IN_MAX 16.00 // Mapped maximum joystick value #define JS_OUT_DEADZONE 1 // Default output deadzone #define JS_OUT_MAX 127 // Output maximum value int BUTTON_MAPPING[INPUT_ACTION_COUNT] = { ACTION_SHORT_PUFF, ACTION_SHORT_SIP, ACTION_LONG_PUFF, ACTION_LONG_SIP, ACTION_VLONG_PUFF, ACTION_VLONG_SIP }; //***DON'T CHANGE THESE CONSTANTS***// #define XHIGH_DIRECTION 1 // Mouthpiece right movements correspond to positive (i.e. right) mouse movement #define XLOW_DIRECTION -1 // Mouthpiece left movements correspond to negative (i.e. left) mouse movement #define YHIGH_DIRECTION -1 // Mouthpiece up movements correspond to negative (i.e. up) mouse movement #define YLOW_DIRECTION 1 // Mouthpiece down movements correspond to positive (i.e. down) mouse movement //*** DEVELOPER CONSTANTS***// - Only change if you know what you're doing. #define DEBUG_MODE false // Enable debug information to serial output (Default: false) #define API_ENABLED true // Enable API Serial interface = true , Disable API serial interface = false #define API_OKAY_RESPONSE 0 #define API_COMMAND_MISSING_RESPONSE 1 #define API_INCORRECT_FORMAT_RESPONSE 2 #define API_INCORRECT_PARAMETER_RESPONSE 3 //***PIN ASSIGNMENTS***// - DO NOT CHANGE #define LED_GREEN_PIN 4 // LipSync LED Color1 : GREEN - digital output pin 5 #define LED_RED_PIN 5 // LipSync LED Color2 : RED - digital outputpin 4 #define BUTTON_DOWN_PIN 7 // Joystick Control Button 2: DOWN - digital input pin 7 (internally pulled-up) #define BUTTON_UP_PIN 8 // Joystick Control Button 1: UP - digital input pin 8 (internally pulled-up) #define TRANS_CONTROL_PIN A3 // Bluetooth Transistor Control Pin - digital output pin A3 #define PIO4_PIN A4 // Bluetooth PIO4_PIN Command Pin - digital output pin A4 #define PRESSURE_PIN A5 // Sip & Puff Pressure Transducer Pin - analog input pin A5 #define X_DIR_HIGH_PIN A0 // X Direction High (Cartesian positive x : right) - analog input pin A0 #define X_DIR_LOW_PIN A1 // X Direction Low (Cartesian negative x : left) - digital output pin A1 #define Y_DIR_HIGH_PIN A2 // Y Direction High (Cartesian positive y : up) - analog input pin A2 #define Y_DIR_LOW_PIN A10 // Y Direction Low (Cartesian negative y : down) - analog input pin A10 const byte UNUSED_PINS[] = {2, // Unused pins 3, 9, 11, 12, 13, 14, 15, 16, 17}; //***LIPSYNC EEPROM MEMORY***// - DO NOT CHANGE #define EEPROM_modelNumber 0 // int:0,1; 255 on fresh Arduino #define EEPROM_sensitivityCounter 2 // int:2,3; #define EEPROM_defaultIsSet 4 // int:4,5; #define EEPROM_yHighComp 6 // float:6,7,8,9; #define EEPROM_yLowComp 10 // float:10,11,12,13; #define EEPROM_xHighComp 14 // float:14,15,16,17; #define EEPROM_xLowComp 18 // float:18,19,20,21; #define EEPROM_xHighMax 22 // int:22,23; #define EEPROM_xLowMax 24 // int:24,25; #define EEPROM_yHighMax 26 // int:26,27; #define EEPROM_yLowMax 28 // int:28,29; #define EEPROM_rotationAngle 30 // int:30,31; #define EEPROM_puffThreshold 32 // int:32,33; #define EEPROM_sipThreshold 34 // int:34,35; #define EEPROM_debugModeEnabled 36 // int:34,35; #define EEPROM_deadzoneValue 38 // int:38,39; #define EEPROM_buttonMode 40 // int:40,41; #define EEPROM_buttonMapping1 42 // int:42,43; #define EEPROM_buttonMapping2 44 // int:44,45; #define EEPROM_buttonMapping3 46 // int:46,47; #define EEPROM_buttonMapping4 48 // int:48,49; #define EEPROM_buttonMapping5 50 // int:50,51; #define EEPROM_buttonMapping6 52 // int:52,53; #define EEPROM_configNumber 54 // int:54,55; 3 when Bluetooth configured //#define EEPROM_compFactor 56 // int:56,57; #define EEPROM_changeTolerance 58 // int:58,59; #define EEPROM_versionNumber 60 // int:60,61; //#define EEPROM_scrollLevel 62 // int:62,63; //#define EEPROM_rawModeEnabled 64 // int:64,65; //***JOYSTICK FUNCTIONS***// - DO NOT CHANGE //Structure for a degree five polynomial typedef struct { float _equationACoef; float _equationBCoef; float _equationCCoef; float _equationDCoef; float _equationECoef; //Coefficient E is 0.00 } _equationCoef; //Initialize the equation coefficient structure for each FSR reading _equationCoef g_xHighEquation = {}; _equationCoef g_xLowEquation = {}; _equationCoef g_yHighEquation = {}; _equationCoef g_yLowEquation = {}; //The input to output (x to y) curve equation using degree five polynomial equation for each sensitivity level _equationCoef g_levelEquation1 = {0.0004,-0.0041,0.0000,-0.0185,1.8000}; _equationCoef g_levelEquation2 = {0.0002,-0.0021,0.0201,-0.3704,4.3000}; _equationCoef g_levelEquation3 = {-0.0008,0.0314,-0.3565,1.2731,3.6056}; _equationCoef g_levelEquation4 = {0.0001,-0.0005,0.0309,-0.4954,7.2167}; _equationCoef g_levelEquation5 = {-0.0004,0.0175,-0.2145,1.0093,5.1333}; _equationCoef g_levelEquation6 = {0.0000,0.0000,0.0000,0.0000,8.4667}; _equationCoef g_levelEquation7 = {-0.0001,0.0062,-0.125,0.7778,9.3000}; _equationCoef g_levelEquation8 = {-0.0004,0.0195,-0.3133,1.6574,10.6889}; _equationCoef g_levelEquation9 = {0.0001,-0.0010,0.0093,-0.9907,21.2444}; _equationCoef g_levelEquation10 = {0.0008,-0.0303,0.5062,-5.1157,35.5500}; _equationCoef g_levelEquation11 = {-0.0001,-0.0051,0.3441,-6.1204,45.4111}; //All sensitivity levels _equationCoef g_levelEquations[11] = {g_levelEquation1, g_levelEquation2, g_levelEquation3, g_levelEquation4, g_levelEquation5, g_levelEquation6, g_levelEquation7, g_levelEquation8, g_levelEquation9, g_levelEquation10, g_levelEquation11}; //***API FUNCTIONS***// - DO NOT CHANGE typedef void (*FunctionPointer)(bool, bool, int*); // Type definition for API function pointer typedef struct // Type definition for API function list { String _command; // Unique two character command code int _parameter; // Parameter that is passed to function FunctionPointer _function; // API function pointer } _functionList; // Declare individual API functions with command, parameter, and corresponding function _functionList getModelNumberFunction = {"MN,0", 0, &getModelNumber}; _functionList getVersionNumberFunction = {"VN,0", 0, &getVersionNumber}; _functionList getJoystickSensitivityFunction = {"SS,0", 0, &getJoystickSensitivity}; _functionList setJoystickSensitivityFunction = {"SS,1", 1, &setJoystickSensitivity}; _functionList getPuffThresholdFunction = {"PT,0", 0, &getPuffThreshold}; _functionList setPuffThresholdFunction = {"PT,1", 1, &setPuffThreshold}; _functionList getSipThresholdFunction = {"ST,0", 0, &getSipThreshold}; _functionList setSipThresholdFunction = {"ST,1", 1, &setSipThreshold}; _functionList getPressureValueFunction = {"PV,0", 0, &getPressureValue}; _functionList getRotationAngleFunction = {"RA,0", 0, &getRotationAngle}; _functionList setRotationAngleFunction = {"RA,1", 1, &setRotationAngle}; _functionList getJoystickValueFunction = {"JV,0", 0, &getJoystickValue}; _functionList getDebugModeFunction = {"DM,0", 0, &getDebugMode}; _functionList setDebugModeFunction = {"DM,1", 1, &setDebugMode}; _functionList getJoystickInitializationFunction = {"IN,0", 0, &getJoystickInitialization}; _functionList setJoystickInitializationFunction = {"IN,1", 1, &setJoystickInitialization}; _functionList getJoystickCalibrationFunction = {"CA,0", 0, &getJoystickCalibration}; _functionList setJoystickCalibrationFunction = {"CA,1", 1, &setJoystickCalibration}; _functionList getButtonMappingFunction = {"MP,0", 0, &getButtonMapping}; _functionList setButtonMappingFunction = {"MP,1", 2, &setButtonMapping}; // 2 denotes an array parameter _functionList getDeadzoneFunction = {"DZ,0", 0, &getDeadzone}; _functionList setDeadzoneFunction = {"DZ,1", 1, &setDeadzone}; _functionList getButtonModeFunction = {"BM,0", 0, &getButtonMode}; _functionList setButtonModeFunction = {"BM,1", 1, &setButtonMode}; _functionList factoryResetFunction = {"FR,1", 1, &factoryReset}; // Declare array of API functions _functionList apiFunction[25] = { getModelNumberFunction, getVersionNumberFunction, getJoystickSensitivityFunction, setJoystickSensitivityFunction, getPuffThresholdFunction, setPuffThresholdFunction, getSipThresholdFunction, setSipThresholdFunction, getPressureValueFunction, getRotationAngleFunction, setRotationAngleFunction, getJoystickValueFunction, getDebugModeFunction, setDebugModeFunction, getJoystickInitializationFunction, setJoystickInitializationFunction, getJoystickCalibrationFunction, setJoystickCalibrationFunction, getButtonMappingFunction, setButtonMappingFunction, getDeadzoneFunction, setDeadzoneFunction, getButtonModeFunction, setButtonModeFunction, factoryResetFunction }; //***GLOBAL VARIABLE DECLARATION***// byte g_modelNumber; // LipSync model number variable byte g_versionNumber; // LipSync version number variable int g_actionButton[INPUT_ACTION_COUNT]; // Sip & Puff action mapping int g_buttonMode; // The button mode variable int g_lastButtonState[6]; // Buttons last states int g_rotationAngle = ROTATION_ANGLE; // Rotation angle variable (degrees) float g_rotationAngle11; // Rotation matrix components float g_rotationAngle12; float g_rotationAngle21; float g_rotationAngle22; byte g_sensitivityCounter; // Variable to track current joystick sensitivity level int g_joystickPressure; // Variable to hold pressure readings int g_sipThreshold; // Sip pressure threshold [ADC steps] int g_puffThreshold; // Puff pressure threshold [ADC steps] unsigned int g_puffCount, g_sipCount; // The puff and long sip incremental counter variables int g_xHighPrev, g_yHighPrev, g_xLowPrev, g_yLowPrev; //Previous FSR reading variables int g_xHighNeutral, g_xLowNeutral, g_yHighNeutral, g_yLowNeutral; //Individual neutral starting positions for each FSR int g_xHighMax, g_xLowMax, g_yHighMax, g_yLowMax; //Max FSR values which are set to the values from EEPROM float g_xHighMapped, g_xLowMapped, g_yHighMapped, g_yLowMapped; //FSR Mapped value float g_xDelta, g_yDelta; //Calculate the x and y delta values const float g_deadband = JOYSTICK_DEADBAND; // Deadband distance from center int g_deadzone; // Declare joystick deadzone variable int g_changeTolerance = CHANGE_DEFAULT_TOLERANCE; // The tolerance of changes in FSRs readings bool g_debugModeEnabled; // Declare debug enable variable bool g_settingsEnabled = false; // Serial input settings command mode enabled or disabled unsigned long g_buttonTimer[2] = {0, 0}; // Buttons time array bool g_buttonPreviousState[2] = {HIGH,HIGH}; // Previous state of buttons //Defining the joystick REPORT_ID and profile type Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_JOYSTICK, 8, 0, true, true, false, false, false, false, false, false, false, false, false); //----------------------------------------------------------------------------------------------------------------------------------- //***MICROCONTROLLER AND PERIPHERAL MODULES CONFIGURATION***// void setup() { Serial.begin(115200); //Set baud rate for serial coms for diagnostic data return from microcontroller initializePins(); // Initialize Arduino input and output pins initializeJoystick(); // Initialize Joystick Joystick.begin(); //Initialize the HID joystick functions delay(1000); getModelNumber(false, false); // Get LipSync model number; Perform factory reset on initial upload. setJoystickInitialization(false, false); // Set the Home joystick and generate movement threshold boundaries getJoystickCalibration(false, false); // Get FSR Max calibration values getFSREquation(); //Get FSR equations getSipThreshold(false, false); // Get the pressure sensor threshold boundaries getPuffThreshold(false, false); // Get the pressure sensor threshold boundaries g_debugModeEnabled = getDebugMode(false, false); // Get the debug mode state g_sensitivityCounter = getJoystickSensitivity(false, false); //Get saved joystick sensitivity parameter from EEPROM and sets the sensitivity counter g_deadzone = getDeadzone(false, false); //Get the deadzone value g_buttonMode = getButtonMode(false , false); //Get saved joystick button mode parameter from EEPROM getButtonMapping(false, false); // Get the input buttons to actions mappings g_rotationAngle = getRotationAngle(false, false); // Read the saved rotation angle from EEPROM updateRotationAngle(); ledBlink(4, 250, 3); // End initialization visual feedback } //----------------------------------------------------------------------------------------------------------------------------------- //***START OF INFINITE LOOP***// void loop() { g_settingsEnabled = serialSettings(g_settingsEnabled); // Check to see if setting option is enabled in Lipsync joystickHandler(); // Read the joystick values and output joystick movements. sipAndPuffHandler(); // Pressure sensor sip and puff functions delay(5); pushButtonHandler(); // Check rear push buttons } //***END OF MAIN LOOP***// //-----------------------------------------------------------------------------------// //-----------------------------------------------------------------------------------// //***INITIALIZE PINS FUNCTION ***// // Function : initializePins // // Description: This function initializes the input/output pins. // // Parameters : void // // Return : void //*********************************// void initializePins(void) { pinMode(LED_GREEN_PIN, OUTPUT); // Set the LED pin 1 as output(GREEN LED) pinMode(LED_RED_PIN, OUTPUT); // Set the LED pin 2 as output(RED LED) pinMode(TRANS_CONTROL_PIN, OUTPUT); // Set the transistor pin as output pinMode(PIO4_PIN, OUTPUT); // Set the bluetooth command mode pin as output pinMode(PRESSURE_PIN, INPUT); // Set the pressure sensor pin input pinMode(X_DIR_HIGH_PIN, INPUT); // Define Force sensor pins as input ( Right FSR ) pinMode(X_DIR_LOW_PIN, INPUT); // Define Force sensor pins as input ( Left FSR ) pinMode(Y_DIR_HIGH_PIN, INPUT); // Define Force sensor pins as input ( Up FSR ) pinMode(Y_DIR_LOW_PIN, INPUT); // Define Force sensor pins as input ( Down FSR ) pinMode(BUTTON_UP_PIN, INPUT_PULLUP); // Set increase sensitivity button pin as input pinMode(BUTTON_DOWN_PIN, INPUT_PULLUP); // Set decrease sensitivity button pin as input // Set unused pins as inputs with pullups for (byte pinIndex = 0; pinIndex < sizeof(UNUSED_PINS); pinIndex++) { pinMode(UNUSED_PINS[pinIndex], INPUT_PULLUP); } } //***INITIALIZE JOYSTICK FUNCTION ***// // Function : initializeJoystick // // Description: This function initializes the joystick. // // Parameters : void // // Return : void //*********************************// void initializeJoystick(void) { Joystick.setXAxisRange(-JS_OUT_MAX, JS_OUT_MAX); //Set the range of joystick X axis Joystick.setYAxisRange(-JS_OUT_MAX, JS_OUT_MAX); //Set the range of joystick y axis //Initialize the last state of buttons g_lastButtonState[0] = 0; g_lastButtonState[1] = 0; g_lastButtonState[2] = 0; g_lastButtonState[3] = 0; g_lastButtonState[4] = 0; g_lastButtonState[5] = 0; } //*** JOYSTICK HANDLER FUNCTION***// // Function : joystickHandler // // Description: This function handles the joystick movements based on the FSR values // // Parameters : void // // Return : void //*********************************// void joystickHandler(void) { // Reset joystick values bool outputJoystick = false; int xJoy = 0; int yJoy = 0; int xHigh = 0; int xLow = 0; int yHigh = 0; int yLow = 0; // Measure FSR joystick and determine whether to output joystick commands outputJoystick = readJoystick(xJoy, yJoy, xHigh, xLow, yHigh, yLow); // Apply rotation to joystick movement based on mounting angle. rotateJoystick(xJoy, yJoy); if (outputJoystick) { // Normal joystick output setXYAxis(xJoy,yJoy); delay(JOYSTICK_DELAY); } //Debug information if (g_debugModeEnabled) { sendDebugRawData(xJoy, yJoy, sipAndPuffRawHandler(), xHigh, xLow, yHigh, yLow); delay(DEBUG_MODE_DELAY); } } //***READ JOYSTICK FUNCTION**// // Function : readJoystick // // Description: This function reads the current FSR values, checks if values exceed deadband, and calculates // joystick movements. Outputs true if mouse should be moved. // // Parameters : xJoy : int : This is the output x joystick value. // yJoy : int : This is the output y joystick value. // xHigh : int : This is the xHigh FSR value. // xLow : int : This is the xLow FSR value. // yHigh : int : This is the yHigh FSR value. // yLow : int : This is the yLow FSR value. // // Return : outputJoystick : bool : This variable is used to indicate if mouse values should be outputted or skipped. //*********************************// bool readJoystick(int &xJoy, int &yJoy, int &xHigh, int &xLow, int &yHigh, int &yLow) { bool outputJoystick = false; // Measure force sensitive resistors xHigh = analogRead(X_DIR_HIGH_PIN); xLow = analogRead(X_DIR_LOW_PIN); yHigh = analogRead(Y_DIR_HIGH_PIN); yLow = analogRead(Y_DIR_LOW_PIN); //Check the FSR changes from previous reading and set the skip flag to true if the changes are below the change tolerance range bool aboveDelta = abs(xHigh - g_xHighPrev) >= g_changeTolerance || abs(xLow - g_xLowPrev) >= g_changeTolerance || abs(yHigh - g_yHighPrev) >= g_changeTolerance || abs(yLow - g_yLowPrev) >= g_changeTolerance; // Store FSR values for next skip check g_xHighPrev = xHigh; g_xLowPrev = xLow; g_yHighPrev = yHigh; g_yLowPrev = yLow; float xHighYHigh = sqrt(sq(((xHigh - g_xHighNeutral) > 0) ? (float)(xHigh - g_xHighNeutral) : 0.0) + sq(((yHigh - g_yHighNeutral) > 0) ? (float)(yHigh - g_yHighNeutral) : 0.0)); //The sq() function raises thr input to power of 2 and is returning the same data type int->int float xHighYLow = sqrt(sq(((xHigh - g_xHighNeutral) > 0) ? (float)(xHigh - g_xHighNeutral) : 0.0) + sq(((yLow - g_yLowNeutral) > 0) ? (float)(yLow - g_yLowNeutral) : 0.0)); //The sqrt() function raises input to power 1/2, returning a float type float xLowYHigh = sqrt(sq(((xLow - g_xLowNeutral) > 0) ? (float)(xLow - g_xLowNeutral) : 0.0) + sq(((yHigh - g_yHighNeutral) > 0) ? (float)(yHigh - g_yHighNeutral) : 0.0)); //These are the vector magnitudes of each quadrant 1-4. Since the FSRs all register float xLowYLow = sqrt(sq(((xLow - g_xLowNeutral) > 0) ? (float)(xLow - g_xLowNeutral) : 0.0) + sq(((yLow - g_yLowNeutral) > 0) ? (float)(yLow - g_yLowNeutral) : 0.0)); //a larger digital value with a positive application force, a large negative difference // Test if radial position is outside circular deadband bool outsideDeadzone = (xHighYHigh > g_deadband) || (xHighYLow > g_deadband) || (xLowYLow > g_deadband) || (xLowYHigh > g_deadband); // If joystick is moved, opposite FSR will decrease in force and therefore decrease in voltate // (e.g. joystick unloaded->high resistance-> low voltage) bool joystickLifted = (xHigh < JOYSTICK_LIFT_THRESOLD) || (xLow < JOYSTICK_LIFT_THRESOLD) || (yHigh < JOYSTICK_LIFT_THRESOLD) || (yLow < JOYSTICK_LIFT_THRESOLD); //Check to see if the joystick has moved outside the deadband if( outsideDeadzone && (aboveDelta || joystickLifted) ) { outputJoystick = true; //Map FSR values to (0 to 16 ) range g_xHighMapped=getMappedFSRValue(xHigh, g_deadzone, g_xHighNeutral, JS_MAPPED_IN_DEADZONE, JS_MAPPED_IN_MAX, g_xHighEquation); g_xLowMapped=getMappedFSRValue(xLow, g_deadzone, g_xLowNeutral, JS_MAPPED_IN_DEADZONE, JS_MAPPED_IN_MAX, g_xLowEquation); g_yHighMapped=getMappedFSRValue(yHigh, g_deadzone, g_yHighNeutral, JS_MAPPED_IN_DEADZONE, JS_MAPPED_IN_MAX, g_yHighEquation); g_yLowMapped=getMappedFSRValue(yLow, g_deadzone, g_yLowNeutral, JS_MAPPED_IN_DEADZONE, JS_MAPPED_IN_MAX, g_yLowEquation); //Calculate the x and y delta values g_xDelta = g_xHighMapped - g_xLowMapped; g_yDelta = g_yHighMapped - g_yLowMapped; //Get the final X and Y output values for Joystick set axis function xJoy = getXYValue(g_xDelta, JS_OUT_DEADZONE, JS_OUT_MAX, g_levelEquations[g_sensitivityCounter]); yJoy = getXYValue(g_yDelta, JS_OUT_DEADZONE, JS_OUT_MAX, g_levelEquations[g_sensitivityCounter]); } //end check deadband else { outputJoystick = true; xJoy = 0; yJoy = 0; } return outputJoystick; } //***ROTATE JOYSTICK FUNCTION ***// // Function : rotateJoystick // // Description: This function applies a rotation to the two input coordinates using the global variable angles. // // Parameters : xJoy : int : the input x joystick value. // yJoy : int : the input y joystick value. // // Return : void //********************// void rotateJoystick(int &xJoy, int &yJoy) { int uJoy = g_rotationAngle11 * xJoy + g_rotationAngle12 * yJoy; // Apply rotation matrix to inputs int vJoy = g_rotationAngle21 * xJoy + g_rotationAngle22 * yJoy; //Update inputs xJoy = uJoy; yJoy = vJoy; } //***SET JOYSTICK OUTPUT X AND Y VALUES FUNCTION***// // Function : setXYAxis // // Description: This function moves the joystick based on the two input coordinates. // // Parameters : x : int : the input x joystick value. // y : int : the input y joystick value. // // Return : void //********************// void setXYAxis(int x, int y) { Joystick.setXAxis(x); Joystick.setYAxis(y); } //***GET X AND Y VALUE IN (-maxOutputValue,maxOutputValue) RANGE FOR HOST DEVICE BASED ON MAPPED FSR VALUE AND THE DEGREE 5 POLYNOMIAL EQUATION COEFFICIENTS FUNCTION***// // Function : getXYValue // // Description: This function returns the mapped joystick value using deadzone and coefficients of joystick equations. // // Parameters : rawValue : float : The raw input value. // deadzoneOutputValue : int : The joystick output deadzone value. // maxOutputValue : int : The joystick output maximum value. // equationCoef : _equationCoef : The coefficients of joystick equation. // // Return : mappedValue : float : The equation coefficient structure to be returned. //*********************************// int getXYValue(float rawValue, int deadzoneOutputValue , int maxOutputValue, _equationCoef equationCoef) { int xySign = sgn(rawValue); //Get the sign of input rawValue = abs(rawValue); //Solve for output regardless of the input sign and multiply the output by the sign ( the polynomial in quadrant 1 and 3 ) int xyValue = (int)((equationCoef._equationACoef*pow(rawValue,5))+(equationCoef._equationBCoef*pow(rawValue,4))+(equationCoef._equationCCoef*pow(rawValue,3))+(equationCoef._equationDCoef*pow(rawValue,2))+(equationCoef._equationECoef*rawValue)); //Coefficient E is 0.00 delay(1); //The points in quadrant 1 and 3 only (mirror (+,+) to (-,-) ) xyValue = (xyValue >= maxOutputValue-deadzoneOutputValue) ? maxOutputValue: (xyValue<=deadzoneOutputValue) ? 0: xyValue; //Set output value to maximum value if it's in maximum deadzone area and set output value to center value if it's in center deadzone area delay(1); xyValue = xySign*xyValue; delay(1); return xyValue; } //***GET MAPPED FSR VALUE BASED ON THE EQUATION COEFFICIENTS FUNCTION***// // Function : getMappedFSRValue // // Description: This function returns the mapped FSR value using deadzone and coefficients of FSR equations. // // Parameters : rawValue : int : The FSR raw input value. // deadzoneInputValue : int : The joystick input deadzone value. // neutralValue : int : The FSR neutral value. // deadzoneOutputValue : float : The joystick output deadzone value. // maxOutputValue : float : The joystick output maximum value. // equationCoef : _equationCoef : The coefficients of FSR equation. // // Return : mappedValue : float : The equation coefficient structure to be returned. //*********************************// float getMappedFSRValue(int rawValue, int deadzoneInputValue, int neutralValue, float deadzoneOutputValue, float maxOutputValue, _equationCoef equationCoef) { float mappedValue; rawValue = (rawValue <= (neutralValue+deadzoneInputValue) && rawValue >=(neutralValue-deadzoneInputValue))? neutralValue:rawValue; //Set input value to neutral value if it's in neutral deadzone area mappedValue = ((equationCoef._equationDCoef*pow(rawValue,2))+(equationCoef._equationECoef*rawValue)); //Solve for mapped FSR Value using the coefficients of the equation ( result : value from 0 to 16 ) mappedValue = (mappedValue>=maxOutputValue-deadzoneOutputValue) ? maxOutputValue: (mappedValue<=deadzoneOutputValue) ? 0.00: mappedValue; //Set output value to maximum value if it's in maximum deadzone area and set output value to center value if it's in center deadzone area return mappedValue; } //***GET THE MAPPED FSR EQUATIONS FUNCTION***// // Function : getFSREquation // // Description: This function retrieves the coefficients of FSR equations. // // Parameters : void // // Return : void //********************// void getFSREquation() { //Create equations to map FSR behavior g_xHighEquation = setFSREquation(g_xHighNeutral,g_xHighMax,JS_MAPPED_IN_NEUTRAL,JS_MAPPED_IN_MAX); delay(10); g_xLowEquation = setFSREquation(g_xLowNeutral,g_xLowMax,JS_MAPPED_IN_NEUTRAL,JS_MAPPED_IN_MAX); delay(10); g_yHighEquation = setFSREquation(g_yHighNeutral,g_yHighMax,JS_MAPPED_IN_NEUTRAL,JS_MAPPED_IN_MAX); delay(10); g_yLowEquation = setFSREquation(g_yLowNeutral,g_yLowMax,JS_MAPPED_IN_NEUTRAL,JS_MAPPED_IN_MAX); delay(10); } //***SET THE EQUATION COEFFICIENTS FOR MAPPING RAW FSR VALUES TO MAPPED VALUE FUNCTION***// // Function : setFSREquation // // Description: This function returns the FSR equation coefficients using two points // // Parameters : x1 : int : Neutral point x coordinate. // x2 : int : Max point x coordinate. // y1 : int : Neutral point y coordinate. // y2 : int : Max point y coordinate. // // Return : resultFactor :_equationCoef : The equation coefficient structure to be returned. //*********************************// _equationCoef setFSREquation(int x1,int x2,int y1,int y2) { //Convert input values from int to float float x1Value = (float)x1; float x2Value = (float)x2; float y1Value = (float)y1; float y2Value = (float)y2; //Solve for coefficient d float dValue = (y2Value - ((y1Value*x2Value)/x1Value))/(x2Value*(x2Value-x1Value)); //Solve for coefficient e float eValue = (y1Value/x1Value)-dValue*x1Value; //Output coefficients ( all others are zero ) _equationCoef resultFactor = {0.00, 0.00, 0.00, dValue, eValue}; return resultFactor; } //***FIND SIGN OF VARIABLE FUNCTION***// // Function : sgn // // Description: This function returns the sign of an integer. // // Parameters : val : int : The integer to return it's sign. // // Return : int8_t : The sign of the integer ( 1 ,or -1 ) //*********************************// int8_t sgn(int val) { if (val < 0) return -1; if (val==0) return 0; return 1; } //***GET MODEL NUMBER FUNCTION***// // Function : getModelNumber // // Description: This function retrieves the current LipSync firmware model number. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// void getModelNumber(bool responseEnabled, bool apiEnabled) { EEPROM.get(EEPROM_modelNumber, g_modelNumber); // Retrieve model number from EEPROM EEPROM.get(EEPROM_versionNumber, g_versionNumber); // Retrieve version number from EEPROM if (g_modelNumber != LIPSYNC_MODEL) { // If the previous firmware was different model then factory reset the settings factoryReset(responseEnabled, apiEnabled, 0); g_modelNumber = LIPSYNC_MODEL; // And store the model number in EEPROM EEPROM.put(EEPROM_modelNumber, g_modelNumber); delay(EEPROM_WRITE_DELAY); } else if (g_versionNumber != LIPSYNC_VERSION) { // If the previous firmware was same model but different version then soft reset the settings factoryReset(responseEnabled, apiEnabled, 1); g_versionNumber = LIPSYNC_VERSION; // And store the version number in EEPROM EEPROM.put(EEPROM_versionNumber, g_versionNumber); delay(EEPROM_WRITE_DELAY); } printResponseSingle(responseEnabled, apiEnabled, true, 0, "MN,0", true, LIPSYNC_MODEL); } //***GET MODEL NUMBER API FUNCTION***// // Function : getModelNumber // // Description: This function is redefinition of main getModelNumber function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void getModelNumber(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 0) { getModelNumber(responseEnabled, apiEnabled); } } //***GET VERSION FUNCTION***// // Function : getVersionNumber // // Description: This function retrieves the current LipSync firmware version number. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// void getVersionNumber(bool responseEnabled, bool apiEnabled) { EEPROM.get(EEPROM_versionNumber, g_versionNumber); if (g_versionNumber != LIPSYNC_VERSION) { //If the previous firmware was different model then factory reset the settings g_versionNumber = LIPSYNC_VERSION; //And store the model number in EEPROM EEPROM.put(EEPROM_versionNumber, g_versionNumber); delay(EEPROM_WRITE_DELAY); } printResponseSingle(responseEnabled, apiEnabled, true, 0, "VN,0", true, LIPSYNC_VERSION); } //***GET VERSION API FUNCTION***// // Function : getVersionNumber // // Description: This function is redefinition of main getVersionNumber function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void getVersionNumber(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 0) { getVersionNumber(responseEnabled, apiEnabled); } } //***GET JOYSTICK SENSITIVITY FUNCTION***// // Function : getJoystickSensitivity // // Description: This function retrieves the current joystick sensitivity level. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// int getJoystickSensitivity(bool responseEnabled, bool apiEnabled) { int sensitivityCounter = SENSITIVITY_COUNTER; if (API_ENABLED) { EEPROM.get(EEPROM_sensitivityCounter, sensitivityCounter); if (sensitivityCounter < 0 || sensitivityCounter > 10) { sensitivityCounter = SENSITIVITY_COUNTER; EEPROM.put(EEPROM_sensitivityCounter, sensitivityCounter); delay(EEPROM_WRITE_DELAY); } } printResponseSingle(responseEnabled, apiEnabled, true, // TODO Add comment for magic argument 0, // TODO Add comment for magic argument "SS,0", true, // TODO Add comment for magic argument sensitivityCounter); return sensitivityCounter; } //***GET JOYSTICK SENSITIVITY API FUNCTION***// // Function : getJoystickSensitivity // // Description: This function is redefinition of main getJoystickSensitivity function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void getJoystickSensitivity(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 0) { getJoystickSensitivity(responseEnabled, apiEnabled); } } //***SET JOYSTICK SENSITIVITY FUNCTION***// // Function : setJoystickSensitivity // // Description: This function sets the current joystick sensitivity level. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inputSensitivityCounter : bool : The new sensitivity level. // // Return : void //*********************************// void setJoystickSensitivity(bool responseEnabled, bool apiEnabled, int inputSensitivityCounter) { bool isValidSpeed = true; if (inputSensitivityCounter >= 0 && inputSensitivityCounter <= 10) // Check if inputSpeedCounter is valid { // Valid inputSensitivityCounter ledBlink(inputSensitivityCounter + 1, 100, 1); g_sensitivityCounter = inputSensitivityCounter; EEPROM.put(EEPROM_sensitivityCounter, g_sensitivityCounter); delay(EEPROM_WRITE_DELAY); if(!API_ENABLED){ g_sensitivityCounter = SENSITIVITY_COUNTER; } isValidSpeed = true; } else { // Invalid inputSensitivityCounter ledBlink(6, 50, 3); EEPROM.get(EEPROM_sensitivityCounter, g_sensitivityCounter); isValidSpeed = false; } byte responseCode = 0; (isValidSpeed) ? responseCode = 0 : responseCode = 3; printResponseSingle(responseEnabled, apiEnabled, isValidSpeed, responseCode, "SS,1", true, // TODO Comment magic argument g_sensitivityCounter); delay(5); } //***SET JOYSTICK SENSITIVITY API FUNCTION***// // Function : setJoystickSensitivity // // Description: This function is redefinition of main setJoystickSensitivity function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inputSpeedCounter : int* : The array of one element which contains the new sensitivity level. // // Return : void void setJoystickSensitivity(bool responseEnabled, bool apiEnabled, int* inputSpeedCounter) { setJoystickSensitivity(responseEnabled, apiEnabled, inputSpeedCounter[0]); } //***INCREASE JOYSTICK SENSITIVITY LEVEL FUNCTION***// // Function : increaseJoystickSensitivity // // Description: This function increases the joystick sensitivity level by one. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// void increaseJoystickSensitivity(bool responseEnabled, bool apiEnabled) { g_sensitivityCounter++; setJoystickSensitivity(responseEnabled, apiEnabled, g_sensitivityCounter); delay(5); } //***DECREASE JOYSTICK SENSITIVITY LEVEL FUNCTION***// // Function : decreaseJoystickSensitivity // // Description: This function decreases the joystick sensitivity level by one. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// void decreaseJoystickSensitivity(bool responseEnabled, bool apiEnabled) { g_sensitivityCounter--; setJoystickSensitivity(responseEnabled, apiEnabled, g_sensitivityCounter); delay(5); } //***READ PRESSURE***// // Function : readPressure // // Description: This function returns a single pressure sensor value in volts // // Parameters : void // // Return : int : The pressure sensor value in ADC steps //*********************************// // This function returns a single pressure sensor value in volts int readPressure(void) { // Measure pressure transducer analog value return analogRead(PRESSURE_PIN); } //***GET PUFF THRESHOLD FUNCTION***// // Function : getPuffThreshold // // Description: This function returns the current puff pressure threshold in percentage and the nominal pressure [0.0V - 5.0V] multiplied by 100. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// void getPuffThreshold(bool responseEnabled, bool apiEnabled) { int pressureNominal = readPressure(); int puffThreshold = PUFF_PRESSURE_THRESHOLD_DEFAULT; if (API_ENABLED) { EEPROM.get(EEPROM_puffThreshold, puffThreshold); if (puffThreshold <= PUFF_PRESSURE_THRESHOLD_MIN || puffThreshold > PUFF_PRESSURE_THRESHOLD_MAX) { EEPROM.put(EEPROM_puffThreshold, PUFF_PRESSURE_THRESHOLD_DEFAULT); delay(EEPROM_WRITE_DELAY); puffThreshold = PUFF_PRESSURE_THRESHOLD_DEFAULT; } } // Create puff pressure threshold value g_puffThreshold = pressureNominal - (puffThreshold / 100.0 * 1023); int pressureValue[] = { puffThreshold, pressureNominal }; printResponseMultiple(responseEnabled, apiEnabled, true, // TODO Comment magic argument 0, // TODO Comment magic argument "PT,0", 2, // Number of values in pressureValue ':', // Delimiter pressureValue); } //***GET PUFF THRESHOLD API FUNCTION***// // Function : getPuffThreshold // // Description: This function is redefinition of main getPuffThreshold function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void getPuffThreshold(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 0) { getPuffThreshold(responseEnabled, apiEnabled); } } //***SET PUFF THRESHOLD FUNCTION***// // Function : setPuffThreshold // // Description: This function sets the current puff pressure threshold in percentage. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inputPuffThreshold : bool : The new puff pressure threshold in percentage. // // Return : void //*********************************// void setPuffThreshold(bool responseEnabled, bool apiEnabled, int inputPuffThreshold) { bool isValidThreshold = true; int puffThreshold = inputPuffThreshold; int pressureNominal = readPressure(); // Read neutral pressure transducer analog value [0-1023] if ( (puffThreshold >= PUFF_PRESSURE_THRESHOLD_MIN) && puffThreshold <= PUFF_PRESSURE_THRESHOLD_MAX) { isValidThreshold = true; EEPROM.put(EEPROM_puffThreshold, puffThreshold); // Update value to memory from serial input delay(EEPROM_WRITE_DELAY); if (!API_ENABLED) { puffThreshold = PUFF_PRESSURE_THRESHOLD_DEFAULT; // If the API is disabled, use the default value from the code } // Update sip and puff pressure threshold variables // Larger values tend to minimize frequency of inadvertent activation g_puffThreshold = pressureNominal - (puffThreshold / 100.0 * 1023); } else { EEPROM.get(EEPROM_puffThreshold, puffThreshold); isValidThreshold = false; } int pressureValue[] = { puffThreshold, pressureNominal }; int responseCode = 0; (isValidThreshold) ? responseCode = 0 : responseCode = 3; printResponseMultiple(responseEnabled, apiEnabled, isValidThreshold, responseCode, "PT,1", 2, // TODO Comment magic argument ':', // TODO Comment magic argument pressureValue); delay(5); } //***SET PUFF THRESHOLD API FUNCTION***// // Function : setPuffThreshold // // Description: This function is redefinition of main setPuffThreshold function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inputPuffThreshold : int* : The array of one element which contains the new pressure threshold. // // Return : void void setPuffThreshold(bool responseEnabled, bool apiEnabled, int* inputPuffThreshold) { setPuffThreshold(responseEnabled, apiEnabled, inputPuffThreshold[0]); } //***GET SIP THRESHOLD FUNCTION***// // Function : getSipThreshold // // Description: This function returns the current sip pressure threshold in percentage and the nominal pressure. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// void getSipThreshold(bool responseEnabled, bool apiEnabled) { int pressureNominal = readPressure(); int sipThreshold = SIP_PRESSURE_THRESHOLD_DEFAULT; if (API_ENABLED) { EEPROM.get(EEPROM_sipThreshold, sipThreshold); delay(EEPROM_WRITE_DELAY); if (sipThreshold <= SIP_PRESSURE_THRESHOLD_MIN || sipThreshold > SIP_PRESSURE_THRESHOLD_MAX) { EEPROM.put(EEPROM_sipThreshold, SIP_PRESSURE_THRESHOLD_DEFAULT); delay(EEPROM_WRITE_DELAY); sipThreshold = SIP_PRESSURE_THRESHOLD_DEFAULT; } } // Create sip pressure threshold value ***Larger values tend to minimize frequency of inadvertent activation g_sipThreshold = pressureNominal + (sipThreshold / 100.0 * 1023); int pressureValue[] = { sipThreshold, pressureNominal }; printResponseMultiple(responseEnabled, apiEnabled, true, // TODO Comment magic argument 0, // TODO Comment magic argument "ST,0", 2, // TODO Comment magic argument ':', // TODO Comment magic argument pressureValue); } //***GET SIP THRESHOLD API FUNCTION***// // Function : getSipThreshold // // Description: This function is redefinition of main getSipThreshold function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void getSipThreshold(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 0) { getSipThreshold(responseEnabled, apiEnabled); } } //***SET SIP THRESHOLD FUNCTION***// // Function : setSipThreshold // // Description: This function sets the current sip pressure threshold in percentage. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inputSipThreshold : bool : The new pressure threshold in percentage. // // Return : void //*********************************// void setSipThreshold(bool responseEnabled, bool apiEnabled, int inputSipThreshold) { bool isValidThreshold; int sipThreshold = inputSipThreshold; int pressureNominal = readPressure(); // Read neutral pressure transducer analog value if ( (sipThreshold >= SIP_PRESSURE_THRESHOLD_MIN) && sipThreshold <= SIP_PRESSURE_THRESHOLD_MAX) { isValidThreshold = true; EEPROM.put(EEPROM_sipThreshold, sipThreshold); // Update value to memory from serial input delay(EEPROM_WRITE_DELAY); if (!API_ENABLED) { sipThreshold = SIP_PRESSURE_THRESHOLD_DEFAULT; // If the API is disabled, use the default value from the code } // Update sip and puff pressure threshold variables g_sipThreshold = pressureNominal + (sipThreshold / 100.0 * 1023); } else { isValidThreshold = false; EEPROM.get(EEPROM_sipThreshold, sipThreshold); } int pressureValue[] = { sipThreshold, pressureNominal }; int responseCode = 0; (isValidThreshold) ? responseCode = 0 : responseCode = 3; printResponseMultiple(responseEnabled, apiEnabled, isValidThreshold, responseCode, "ST,1", 2, // TODO Comment magic argument ':', // TODO Comment magic argument pressureValue); } //***SET PRESSURE THRESHOLD API FUNCTION***// // Function : setPressureThreshold // // Description: This function is redefinition of main setPressureThreshold function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inputPressureThreshold : int* : The array of one element which contains the new pressure threshold. // // Return : void void setSipThreshold(bool responseEnabled, bool apiEnabled, int* inputSipThreshold) { setSipThreshold(responseEnabled, apiEnabled, inputSipThreshold[0]); } //***GET PRESSURE VALUE FUNCTION***// // Function : getPressureValue // // Description: This function returns pressure value in steps [0-1023]. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// void getPressureValue(bool responseEnabled, bool apiEnabled) { int tempPressureValue = readPressure(); printResponseSingle(responseEnabled, apiEnabled, true, 0, "PV,0", true, tempPressureValue); } //***GET PRESSURE VALUE API FUNCTION***// // Function : getPressureValue // // Description: This function is redefinition of main getPressureValue function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void getPressureValue(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 0) { getPressureValue(responseEnabled, apiEnabled); } } //***GET JOYSTICK VALUE FUNCTION***// // Function : getJoystickValue // // Description: This function returns a set of single FSR measurements. // Output format: "JV,0:xHigh,xLow,yHigh,yLow" // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// void getJoystickValue(bool responseEnabled, bool apiEnabled) { int xHighTemp = analogRead(X_DIR_HIGH_PIN); // Read analog values of FSR's : A0 int xLowTemp = analogRead(X_DIR_LOW_PIN); // Read analog values of FSR's : A1 int yHighTemp = analogRead(Y_DIR_HIGH_PIN); // Read analog values of FSR's : A0 int yLowTemp = analogRead(Y_DIR_LOW_PIN); // Read analog values of FSR's : A10 int joystickTempValue[] = { xHighTemp, xLowTemp, yHighTemp, yLowTemp }; printResponseMultiple(responseEnabled, apiEnabled, true, // TODO Comment magic argument 0, // TODO Comment magic argument "JV,0", // Command 4, // 4 output variables ',', // Delimiter between output variables joystickTempValue); } //***GET JOYSTICK VALUE API FUNCTION***// // Function : getJoystickValue // // Description: This function is redefinition of main getJoystickValue function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void getJoystickValue(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 0) { getJoystickValue(responseEnabled, apiEnabled); } } //***GET DEBUG MODE STATE FUNCTION***// // Function : getDebugMode // // Description: This function retrieves the state of debug mode. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : debugState : bool : The current state of debug mode. //*********************************// bool getDebugMode(bool responseEnabled, bool apiEnabled) { bool debugState = DEBUG_MODE; int debugIntValue; if (API_ENABLED) { EEPROM.get(EEPROM_debugModeEnabled, debugIntValue); if (debugIntValue != 0 && debugIntValue != 1) // TODO Comment magic argument { EEPROM.put(EEPROM_debugModeEnabled, DEBUG_MODE); delay(EEPROM_WRITE_DELAY); debugState = DEBUG_MODE; } } else { debugState = DEBUG_MODE; } printResponseSingle(responseEnabled, apiEnabled, true, // TODO Comment magic argument 0, // TODO Comment magic argument "DM,0", true,// TODO Comment magic argument debugState); if(responseEnabled && debugState==1){ sendDebugConfigData();} return debugState; } //***GET DEBUG MODE STATE API FUNCTION***// // Function : getDebugMode // // Description: This function is redefinition of main getDebugMode function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void getDebugMode(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 0) { getDebugMode(responseEnabled, apiEnabled); } } //***SET DEBUG MODE STATE FUNCTION***// // Function : setDebugMode // // Description: This function sets the state of debug mode. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inpuDebugState : int : The new debug mode state ( true = ON , false = OFF ) // // Return : void //*********************************// void setDebugMode(bool responseEnabled, bool apiEnabled, int inpuDebugState) { bool isValidDebugState = true; // TODO Should this default to false? if (inpuDebugState == 0 || inpuDebugState == 1) { g_debugModeEnabled = inpuDebugState; EEPROM.put(EEPROM_debugModeEnabled, g_debugModeEnabled); delay(EEPROM_WRITE_DELAY); if (!API_ENABLED) { g_debugModeEnabled = DEBUG_MODE; } isValidDebugState = true; } else { isValidDebugState = false; } delay(5); int responseCode = 0; (isValidDebugState) ? responseCode = 0 : responseCode = 3; printResponseSingle(responseEnabled, apiEnabled, isValidDebugState, responseCode, "DM,1", true, // TODO Comment magic argument g_debugModeEnabled); if(inpuDebugState==1) { sendDebugConfigData(); } } //***SET DEBUG MODE STATE API FUNCTION***// // Function : setDebugMode // // Description: This function is redefinition of main setDebugMode function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inpuDebugState : int* : The array of one element which contains the new debug mode state. // // Return : void void setDebugMode(bool responseEnabled, bool apiEnabled, int* inpuDebugState) { setDebugMode(responseEnabled, apiEnabled, inpuDebugState[0]); } //***SEND DEBUG DATA FUNCTION***// // Function : sendDebugConfigData // // Description: This function serial prints the debug mode config data. // Output format: "LOG:1:0,0,0,g_xHighNeutral,g_xLowNeutral,g_yHighNeutral,g_yLowNeutral" // Output format: "LOG:2:0,0,0,g_xHighMax,g_xLowMax,g_yHighMax,g_yLowMax" // // Parameters : void // // Return : void //*********************************// void sendDebugConfigData() { int neutralValue[] = {0, 0, 0, g_xHighNeutral, g_xLowNeutral, g_yHighNeutral, g_yLowNeutral}; int maxValue[] = {0, 0, 0, g_xHighMax, g_xLowMax, g_yHighMax, g_yLowMax}; delay(100); // TODO This seems like a super long delay. printResponseContinuous("LOG", 1, 7, ',', neutralValue); delay(100); printResponseContinuous("LOG", 2, 7, ',', maxValue); delay(100); } //***SEND DEBUG RAW DATA FUNCTION***// // Function : sendDebugRawData // // Description: This function serial prints the debug mode raw data. // Output format: "LOG:3:xJoy,yJoy,Action,xUp,xDown,yUp,yDown" // // Parameters : x : int : The Joystick x movement. // y : int : The Joystick y movement. // action : int : The Joystick button actions. // xUp : int : The xUp FSR value. // xDown : int : The xDown FSR value. // yUp : int : The yUp FSR value. // yDown : int : The yDown FSR value. // // Return : void //*********************************// void sendDebugRawData(int x, int y, int action, int xUp, int xDown, int yUp, int yDown) { int rawDataValue[] = {x, y, action, xUp, xDown, yUp, yDown}; printResponseContinuous("LOG", 3, 7, ',', rawDataValue); } //***GET JOYSTICK INITIALIZATION FUNCTION***// /// Function : getJoystickInitialization // // Description: This function retrieves the FSR Neutral values from joystick Initialization. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// void getJoystickInitialization(bool responseEnabled, bool apiEnabled) { int neutralValue[] = {g_xHighNeutral, g_xLowNeutral, g_yHighNeutral, g_yLowNeutral}; printResponseMultiple(responseEnabled, apiEnabled, true, //TODO Comment magic argument 0, //TODO Comment magic argument "IN,0", 4, //TODO Comment magic argument ',', //TODO Comment magic argument neutralValue); } //***GET JOYSTICK INITIALIZATION API FUNCTION***// // Function : getJoystickInitialization // // Description: This function is redefinition of main getJoystickInitialization function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void getJoystickInitialization(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 0) { getJoystickInitialization(responseEnabled, apiEnabled); } } //***SET JOYSTICK INITIALIZATION FUNCTION***// /// Function : setJoystickInitialization // // Description: This function performs joystick Initialization. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // mode : int : The comp factor mode used during the joystick Initialization. // Get comp factors from memory if mode set to 1. // Set comp factors to memory if mode set to 2. // // Return : void //*********************************// void setJoystickInitialization(bool responseEnabled, bool apiEnabled) { ledOn(1); //Turn on Green LED int xHigh = analogRead(X_DIR_HIGH_PIN); // Set the initial neutral x-high value of joystick int xLow = analogRead(X_DIR_LOW_PIN); // Set the initial neutral x-low value of joystick int yHigh = analogRead(Y_DIR_HIGH_PIN); // Set the initial neutral y-high value of joystick int yLow = analogRead(Y_DIR_LOW_PIN); // Set the initial Initial neutral y-low value of joystick //Set the neutral values and change detection g_xHighPrev = g_xHighNeutral = xHigh; g_xLowPrev = g_xLowNeutral = xLow; g_yHighPrev = g_yHighNeutral = yHigh; g_yLowPrev = g_yLowNeutral = yLow; int neutralValue[] = {g_xHighNeutral, g_xLowNeutral, g_yHighNeutral, g_yLowNeutral}; printResponseMultiple(responseEnabled, apiEnabled, true,//TODO Comment magic argument 0, //TODO Comment magic argument "IN,1", 4,//TODO Comment magic argument ',',//TODO Comment magic argument neutralValue); ledClear(); } //***SET JOYSTICK INITIALIZATION API FUNCTION***// // Function : setJoystickInitialization // // Description: This function is redefinition of main setJoystickInitialization function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // mode : int* : The array of one element which contains the initialization mode. // // Return : void void setJoystickInitialization(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 1) { setJoystickInitialization(responseEnabled, apiEnabled); } } //*** GET JOYSTICK CALIBRATION FUNCTION***// /// Function : getJoystickCalibration // // Description: This function retrieves FSR maximum values from joystick Calibration. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// void getJoystickCalibration(bool responseEnable, bool apiEnabled) { // Get the max values from Memory EEPROM.get(EEPROM_xHighMax, g_xHighMax); EEPROM.get(EEPROM_xLowMax, g_xLowMax); EEPROM.get(EEPROM_yHighMax, g_yHighMax); EEPROM.get(EEPROM_yLowMax, g_yLowMax); int maxValue[] = { g_xHighMax, g_xLowMax, g_yHighMax, g_yLowMax }; printResponseMultiple(responseEnable, apiEnabled, true, //TODO Comment magic argument 0, "CA,0", // Command code, get 4, // Number of output arguments ',', // Delimiter maxValue); } //***GET JOYSTICK CALIBRATION API FUNCTION***// // Function : getJoystickCalibration // // Description: This function is redefinition of main getJoystickCalibration function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void getJoystickCalibration(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 0) { getJoystickCalibration(responseEnabled, apiEnabled); } } //*** SET JOYSTICK CALIBRATION FUNCTION***// /// Function : getJoystickCalibration // // Description: This function starts the joystick Calibration. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// void setJoystickCalibration(bool responseEnabled, bool apiEnabled) { ledClear(); printResponseSingle(responseEnabled, apiEnabled, true, 0, "CA,1", true, 0); ledBlink(4, 300, 3); printResponseSingle(responseEnabled, apiEnabled, true, 0, "CA,1", true, 1); ledBlink(6, 500, 1); g_yHighMax = analogRead(Y_DIR_HIGH_PIN); ledBlink(1, 1000, 2); printResponseSingle(responseEnabled, apiEnabled, true, 0, "CA,1", true, 2); ledBlink(6, 500, 1); g_xHighMax = analogRead(X_DIR_HIGH_PIN); ledBlink(1, 1000, 2); printResponseSingle(responseEnabled, apiEnabled, true, 0, "CA,1", true, 3); ledBlink(6, 500, 1); g_yLowMax = analogRead(Y_DIR_LOW_PIN); ledBlink(1, 1000, 2); printResponseSingle(responseEnabled, apiEnabled, true, 0, "CA,1", true, 4); ledBlink(6, 500, 1); g_xLowMax = analogRead(X_DIR_LOW_PIN); ledBlink(1, 1000, 2); EEPROM.put(EEPROM_xHighMax, g_xHighMax); delay(EEPROM_WRITE_DELAY); EEPROM.put(EEPROM_xLowMax, g_xLowMax); delay(EEPROM_WRITE_DELAY); EEPROM.put(EEPROM_yHighMax, g_yHighMax); delay(EEPROM_WRITE_DELAY); EEPROM.put(EEPROM_yLowMax, g_yLowMax); delay(EEPROM_WRITE_DELAY); ledBlink(5, 250, 3); int maxValue[] = { g_xHighMax, g_xLowMax, g_yHighMax, g_yLowMax }; printResponseMultiple(responseEnabled, apiEnabled, true, 0, "CA,1:5", 4, ',', maxValue); } //***SET JOYSTICK CALIBRATION API FUNCTION***// // Function : setJoystickCalibration // // Description: This function is redefinition of main setJoystickCalibration function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void setJoystickCalibration(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 1) { setJoystickCalibration(responseEnabled, apiEnabled); } } //***GET BUTTON MAPPING FUNCTION***// // Function : getButtonMapping // // Description: This function retrieves a new input button action mapping. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// void getButtonMapping(bool responseEnabled, bool apiEnabled) { bool isValidMapping = true; if (API_ENABLED) { for (byte i = 0; i < INPUT_ACTION_COUNT; i++) { // Check if it's a valid mapping int buttonMapping; EEPROM.get(EEPROM_buttonMapping1 + i * 2, buttonMapping); if (buttonMapping < 0 || buttonMapping > 8) { isValidMapping = false; break; } else { g_actionButton[i] = buttonMapping; } } if (!isValidMapping) { for (byte i = 0; i < INPUT_ACTION_COUNT; i++) { // Save the default mapping into EEPROM if it's not a valid mapping EEPROM.put(EEPROM_buttonMapping1 + i * 2, BUTTON_MAPPING[i]); delay(EEPROM_WRITE_DELAY); g_actionButton[i] = BUTTON_MAPPING[i]; } } } printResponseMultiple(responseEnabled, apiEnabled, true, 0, "MP,0", 6 , '\0', g_actionButton); delay(5); } //***GET BUTTON MAPPING API FUNCTION***// // Function : getButtonMapping // // Description: This function is redefinition of main getButtonMapping function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void getButtonMapping(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 0) { getButtonMapping(responseEnabled, apiEnabled); } } //***SET BUTTON MAPPING FUNCTION***// // Function : setButtonMapping // // Description: This function sets a new input button action mapping. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inputButtonMapping : int array : The input button action mapping requested. // // Return : void //*********************************// void setButtonMapping(bool responseEnabled, bool apiEnabled, int inputButtonMapping[]) { bool isValidMapping = true; for (byte i = 0; i < INPUT_ACTION_COUNT; i++) { // Check each action for validity if (inputButtonMapping[i] < 0 || inputButtonMapping[i] > 8) // Up to 8 input actions but 6 available { isValidMapping = false; break; } } if (isValidMapping) { //Valid mapping for (byte i = 0; i < INPUT_ACTION_COUNT; i++) { EEPROM.put(EEPROM_buttonMapping1 + i * 2, inputButtonMapping[i]); // Save the mapping into EEPROM if it's a valid mapping delay(EEPROM_WRITE_DELAY); g_actionButton[i] = inputButtonMapping[i]; } if (!API_ENABLED) { memcpy(g_actionButton, BUTTON_MAPPING, INPUT_ACTION_COUNT); } } int responseCode = 0; (isValidMapping) ? responseCode = 0 : responseCode = 3; printResponseMultiple(responseEnabled, apiEnabled, isValidMapping, responseCode, "MP,1", 6, '\0', g_actionButton); } //***GET ROTATION ANGLE FUNCTION***/// // Function : getRotationAngle // // Description: This function gets the current rotation angle {0,90,180,270} // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : tempRotationAngle : int : The current rotation angle {0,90,180,270} //*********************************// int getRotationAngle(bool responseEnabled, bool apiEnabled) { int tempRotationAngle = ROTATION_ANGLE; if (API_ENABLED) { EEPROM.get(EEPROM_rotationAngle, tempRotationAngle); // Get the rotation angle from memory } else { tempRotationAngle = ROTATION_ANGLE; } printResponseSingle(responseEnabled, apiEnabled, true, 0, "RA,0", true, tempRotationAngle); return tempRotationAngle; } //***GET ROTATION ANGLE API FUNCTION***// // Function : getRotationAngle // // Description: This function is redefinition of main getRotationAngle function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true.s // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void getRotationAngle(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 0) { getRotationAngle(responseEnabled, apiEnabled); } } //***SET ROTATION ANGLE FUNCTION***/// // Function : setRotationAngle // // Description: This function sets a new rotation angle {0,90,180,270} // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inputRotationAngle : int : The input rotation angle {0,90,180,270} requested. // // Return : void //*********************************// void setRotationAngle(bool responseEnabled, bool apiEnabled, int inputRotationAngle) { bool isValidRotationAngle = true; if ( inputRotationAngle == 0 || inputRotationAngle == 90 || inputRotationAngle == 180 || inputRotationAngle == 270) { isValidRotationAngle = true; g_rotationAngle = inputRotationAngle; // Update value to global variable EEPROM.put(EEPROM_rotationAngle, g_rotationAngle); // Update value to memory from serial input delay(EEPROM_WRITE_DELAY); if (!API_ENABLED) { g_rotationAngle = ROTATION_ANGLE; // Use default rotation angle if bad serial input } } else { isValidRotationAngle = false; } int responseCode = 0; (isValidRotationAngle) ? responseCode = 0 : responseCode = 3; printResponseSingle(responseEnabled, apiEnabled, isValidRotationAngle, responseCode, "RA,1", true, g_rotationAngle); updateRotationAngle(); // Update rotation transform } //***SET ROTATION ANGLE API FUNCTION***// // Function : setRotationAngle // // Description: This function is redefinition of main setRotationAngle function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inputRotationAngle : int* : The array of one element which contains the new rotation angle. // // Return : void void setRotationAngle(bool responseEnabled, bool apiEnabled, int* inputRotationAngle) { setRotationAngle(responseEnabled, apiEnabled, inputRotationAngle[0]); } //***UPDATE ROTATION ANGLES FUNCTION***/// // Function : updateRotationAngle // // Description: This function updates global rotation angles. // // Parameters : void // // Return : void //***************************// void updateRotationAngle(void) { // Set rotation angle components based on global rotation angle // Currently limited to 4 cadrinal switch(g_rotationAngle) { case 90: { g_rotationAngle11 = 0; g_rotationAngle12 = -1; g_rotationAngle21 = -1; g_rotationAngle22 = 0; break; } case 180: { g_rotationAngle11 = -1; g_rotationAngle12 = 0; g_rotationAngle21 = 0; g_rotationAngle22 = 1; break; } case 270: { g_rotationAngle11 = 0; g_rotationAngle12 = 1; g_rotationAngle21 = 1; g_rotationAngle22 = 0; break; } case 0: { } default: { // Default rotation angle g_rotationAngle11 = 1; g_rotationAngle12 = 0; g_rotationAngle21 = 0; g_rotationAngle22 = -1; break; } } // End switch case } //***GET DEADZONE FUNCTION***// // Function : getDeadzone // // Description: This function retrieves the current deadzone. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// int getDeadzone(bool responseEnabled, bool apiEnabled) { int deadzone = JOYSTICK_DEADBAND; if (API_ENABLED) { EEPROM.get(EEPROM_deadzoneValue, deadzone); if (deadzone < JOYSTICK_DEADBAND || deadzone> JOYSTICK_MAX_DEADZONE) { deadzone = JOYSTICK_DEADBAND; EEPROM.put(EEPROM_deadzoneValue, deadzone); delay(EEPROM_WRITE_DELAY); } } printResponseSingle(responseEnabled, apiEnabled, true, 0, "DZ,0", true, deadzone); return deadzone; } //***GET DEADZONE API FUNCTION***// // Function : getDeadzone // // Description: This function is redefinition of main getDeadzone function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void getDeadzone(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 0) { getDeadzone(responseEnabled, apiEnabled); } } //***SET DEADZONE FUNCTION***// // Function : setDeadzone // // Description: This function sets the deadzone. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inputDeadzone : int : The new the deadzone. // // Return : void //*********************************// void setDeadzone(bool responseEnabled, bool apiEnabled, int inputDeadzone) { bool isValidFactor = true; if (inputDeadzone >= JOYSTICK_DEADBAND && inputDeadzone <= JOYSTICK_MAX_DEADZONE) // Check if inputDeadzone is within range { // Valid inputDeadzone g_deadzone = inputDeadzone; EEPROM.put(EEPROM_deadzoneValue, inputDeadzone); delay(EEPROM_WRITE_DELAY); if(!API_ENABLED){ g_deadzone = JOYSTICK_DEADBAND; } isValidFactor = true; } else { //Invalid inputDeadzone EEPROM.get(EEPROM_deadzoneValue, g_deadzone); delay(10); isValidFactor = false; } int responseCode = 0; (isValidFactor) ? responseCode = 0 : responseCode = 3; printResponseSingle(responseEnabled, apiEnabled, isValidFactor, responseCode, "DZ,1", true, g_deadzone); } //***SET BUTTON MODE API FUNCTION***// // Function : setDeadzone // // Description: This function is redefinition of main setDeadzone function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inputDeadzone : int* : The array of one element which contains the new deadzone. // // Return : void void setDeadzone(bool responseEnabled, bool apiEnabled, int* inputDeadzone) { setDeadzone(responseEnabled, apiEnabled, inputDeadzone[0]); } //***GET BUTTON MODE FUNCTION***// // Function : getButtonMode // // Description: This function retrieves the current button mode. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // // Return : void //*********************************// int getButtonMode(bool responseEnabled, bool apiEnabled) { int buttonMode = BUTTON_MODE; if (API_ENABLED) { EEPROM.get(EEPROM_buttonMode, buttonMode); if (buttonMode != BUTTON_DIGITAL_MODE && buttonMode != BUTTON_ANALOG_MODE) { buttonMode = BUTTON_MODE; EEPROM.put(EEPROM_buttonMode, buttonMode); delay(EEPROM_WRITE_DELAY); } } printResponseSingle(responseEnabled, apiEnabled, true, 0, "BM,0", true, buttonMode); return buttonMode; } //***GET BUTTON MODE API FUNCTION***// // Function : getButtonMode // // Description: This function is redefinition of main getButtonMode function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // optionalArray : int* : The array of int which should contain one element with value of zero. // // Return : void void getButtonMode(bool responseEnabled, bool apiEnabled, int* optionalArray) { if (optionalArray[0] == 0) { getButtonMode(responseEnabled, apiEnabled); } } //***SET BUTTON MODE FUNCTION***// // Function : setButtonMode // // Description: This function sets the button mode. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inputButtonMode : bool : The new the button mode. // // Return : void //*********************************// void setButtonMode(bool responseEnabled, bool apiEnabled, int inputButtonMode) { bool isValidFactor = true; if (inputButtonMode == BUTTON_DIGITAL_MODE || inputButtonMode == BUTTON_ANALOG_MODE) // Check if inputButtonMode is within range { // Valid inputButtonMode g_buttonMode = inputButtonMode; EEPROM.put(EEPROM_buttonMode, g_buttonMode); delay(EEPROM_WRITE_DELAY); if(!API_ENABLED){ g_buttonMode = BUTTON_MODE; } isValidFactor = true; } else { //Invalid inputButtonMode EEPROM.get(EEPROM_buttonMode, g_buttonMode); delay(10); isValidFactor = false; } int responseCode = 0; (isValidFactor) ? responseCode = 0 : responseCode = 3; printResponseSingle(responseEnabled, apiEnabled, isValidFactor, responseCode, "BM,1", true, g_buttonMode); } //***SET BUTTON MODE API FUNCTION***// // Function : setButtonMode // // Description: This function is redefinition of main setButtonMode function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // inputButtonMode : int* : The array of one element which contains the new button mode. // // Return : void void setButtonMode(bool responseEnabled, bool apiEnabled, int* inputButtonMode) { setButtonMode(responseEnabled, apiEnabled, inputButtonMode[0]); } //***FACTORY RESET FUNCTION***// // Function : factoryReset // // Description: This function performs factory reset. It can perform a soft or hard reset. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // resetType : int : The reset type ( 0 = hard reset, 1 = soft reset) // // Return : void //***************************// void factoryReset(bool responseEnabled, bool apiEnabled, int resetType) { bool isValidResetType; int responseCode = 0; if (resetType == 0 || resetType == 1) { // Reset following settings only if a factory reset is performed isValidResetType = true; responseCode = 0; if (resetType == 0) { // HARD RESET // Resets pressure thresholds and button mapping to default setPuffThreshold(false, true, PUFF_PRESSURE_THRESHOLD_DEFAULT); // Set default pressure threshold setSipThreshold(false, true, SIP_PRESSURE_THRESHOLD_DEFAULT); // Set default pressure threshold setButtonMapping(false, true, BUTTON_MAPPING); // Set default action mapping } setJoystickSensitivity(false, true, SENSITIVITY_COUNTER); // Set default sensitive counter setRotationAngle(false, true, ROTATION_ANGLE); // Set default rotation angle setDebugMode(false, true, DEBUG_MODE); // Set default debug mode setDeadzone(false, true, JOYSTICK_DEADBAND); // Set default deadzone setButtonMode(false, true, BUTTON_MODE); // Set default button mode g_sensitivityCounter = SENSITIVITY_COUNTER; g_debugModeEnabled = DEBUG_MODE; g_deadzone = JOYSTICK_DEADBAND; g_buttonMode = BUTTON_MODE; ledBlink(2, 250, 1); } else { isValidResetType = false; responseCode = 3; //TODO Add comment with what this means } printResponseSingle(responseEnabled, apiEnabled, isValidResetType, responseCode, "FR,1", true, resetType); } //***FACTORY RESET API FUNCTION***// // Function : factoryReset // // Description: This function is redefinition of main factoryReset function to match the types of API function arguments. // // Parameters : responseEnabled : bool : The response for serial printing is enabled if it's set to true. // The serial printing is ignored if it's set to false. // apiEnabled : bool : The API response is sent if it's set to true. // Manual response is sent if it's set to false. // resetType : int* : The array of one element which contains the reset type. // // Return : void void factoryReset(bool responseEnabled, bool apiEnabled, int* resetType) { factoryReset(responseEnabled, apiEnabled, resetType[0]); } //***SERIAL SETTINGS FUNCTION TO CHANGE SPEED AND COMMUNICATION MODE USING SOFTWARE***// // Function : serialSettings // // Description: This function confirms if serial settings should be enabled. // It returns true if it's in the settings mode and is waiting for a command. // It returns false if it's not in the settings mode or it needs to exit the settings mode. // // Parameters : enabled : bool : The input flag // // Return : bool //*************************************************************************************// bool serialSettings(bool enabled) { String commandString = ""; bool settingsFlag = enabled; // Settings mode or command mode bool responseSendFlag = false; // Send response if true , perform command if false bool responseStatusFlag = false; // Set status of the response ( SUCCESS = true, FAIL = false ) // Set the input parameter to the flag returned. This will help to detect that the settings actions should be performed. if (Serial.available() > 0) { // Check if serial has received or read input string and word "SETTINGS" is in input string. commandString = Serial.readString(); if (settingsFlag == false && commandString == "SETTINGS") { // SETTING received // Set the return flag to true so settings actions can be performed in the next call to the function settingsFlag = true; responseSendFlag = true; responseStatusFlag = true; } else if (settingsFlag == true && commandString == "EXIT") { // EXIT Recieved // Set the return flag to false so settings actions can be exited settingsFlag = false; responseSendFlag = true; responseStatusFlag = true; } else if (settingsFlag == true && isValidCommandFormat(commandString)) { // Check if command's format is correct and it's in settings mode settingsFlag = false; responseSendFlag = false; } else { settingsFlag = false; responseSendFlag = true; responseStatusFlag = false; } // Perform action based on the previous conditional statements (responseSendFlag) ? printResponseSingle(true, true, responseStatusFlag, 0, commandString, false, 0) : performCommand(commandString); Serial.flush(); } return settingsFlag; } //***VALIDATE INPUT COMMAND FORMAT FUNCTION***// // Function : isValidCommandFormat // // Description: This function confirms command string has correct format. // It returns true if the string has a correct format. // It returns false if the string doesn't have a correct format. // // Parameters : inputCommandString : String : The input string // // Return : boolean //***********************************************// bool isValidCommandFormat(String inputCommandString) { bool isValidFormat = false; int inputLength = inputCommandString.length(); if ((inputLength >= (6) && inputLength <= (11)) && inputCommandString.charAt(2) == ',' && inputCommandString.charAt(4) == ':') { isValidFormat = true; } return isValidFormat; } //***CHECK IF STRING IS A NUMBER FUNCTION***// // Function : isStrNumber // // Description: This function checks if the input string is a number. // It returns true if the string includes all numeric characters. // It returns false if the string includes a non numeric character. // // Parameters : str : String : The input string // // Return : boolean //******************************************// boolean isStrNumber(String str) { for (byte i = 0; i < str.length(); i++) { if (!isDigit(str.charAt(i))) { return false; } } return true; } //***CHECK IF CHAR IS A VALID DELIMITER FUNCTION***// // Function : isValidDelimiter // // Description: This function checks if the input char is a valid delimiter. // It returns true if the character is a valid delimiter. // It returns false if the character is not a valid delimiter. // // Parameters : inputDelimiter : char : The input char delimiter // // Return : boolean //******************************************// bool isValidDelimiter(char inputDelimiter) { bool validOutput; (inputDelimiter == ',' || inputDelimiter == ':' || inputDelimiter == '-') ? validOutput = true : validOutput = false; return validOutput; } //***SERIAL PRINT OUT COMMAND RESPONSE WITH SINGLE PARAMETER FUNCTION***// // Function : printResponseSingle // // Description: Serial Print output of the responses from APIs with single parameter as the output // // Parameters : responseEnabled : bool : Print the response if it's set to true, and skip the response if it's set to false. // apiEnabled : bool : Print the response and indicate if the the function was called via the API if it's set to true. // Print Manual response if the function wasn't called via API. // responseStatus : bool : The response status (SUCCESS,FAIL) // responseNumber : int : 0,1,2 (Different meanings depending on the responseStatus) // responseCommand : String : The End-Point command which is returned as output. // responseParameterEnabled : bool : Print the parameter if it's set to true, and skip the parameter if it's set to false. // responseParameter : int : The response parameters printed as output. // // Return : void //***********************************************************************// void printResponseSingle(bool responseEnabled, bool apiEnabled, bool responseStatus, int responseNumber, String responseCommand, bool responseParameterEnabled, int responseParameter) { if (responseEnabled) { if (responseStatus) { (apiEnabled) ? Serial.print("SUCCESS") : Serial.print("MANUAL"); } else { Serial.print("FAIL"); } Serial.print(","); Serial.print(responseNumber); Serial.print(":"); Serial.print(responseCommand); if (responseParameterEnabled) { Serial.print(":"); Serial.println(responseParameter); } else { Serial.println(""); } delay(SERIAL_DELAY); } } //***SERIAL PRINT OUT COMMAND RESPONSE WITH MULTIPLE PARAMETERS FUNCTION***// // Function : printResponseMultiple // // Description: Serial Print output of the responses from APIs with multiple parameters // // Parameters : responseEnabled : bool : Print the response if it's set to true, and skip the response if it's set to false. // apiEnabled : bool : Print the response and indicate if the the function was called via the API if it's set to true. // Print Manual response if the function wasn't called via API. // responseStatus : bool : The response status (SUCCESS,FAIL) // responseNumber : byte : 0,1,2,3 (Different meanings depending on the responseStatus) // responseCommand : String : The End-Point command which is returned as output. // responsePrefix : String : The prefix to be added before the parameter section of the response. // responseParameterSize : byte : The size of the array which holds output response parameters. // responseParameterDelimiter : char array : The delimiter used to separate multiple response parameters. // responseParameter : int array : The response parameters printed as output. // // Return : void //************************************************************************************// void printResponseMultiple(bool responseEnabled, bool apiEnabled, bool responseStatus, byte responseNumber, String responseCommand, byte responseParameterSize, char responseParameterDelimiter, int responseParameter[]) { char tempParameterDelimiter[1]; (isValidDelimiter(responseParameterDelimiter)) ? tempParameterDelimiter[0] = {responseParameterDelimiter} : tempParameterDelimiter[0] = {'\0'}; if (responseEnabled) { if (responseStatus) { (apiEnabled) ? Serial.print("SUCCESS") : Serial.print("MANUAL"); } else { Serial.print("FAIL"); } Serial.print(","); Serial.print(responseNumber); Serial.print(":"); Serial.print(responseCommand); Serial.print(":"); for (byte parameterIndex = 0; parameterIndex < responseParameterSize; parameterIndex++) { Serial.print(responseParameter[parameterIndex]); if (parameterIndex < (responseParameterSize - 1) && tempParameterDelimiter[0] != '\0') { Serial.print(tempParameterDelimiter[0]); } } Serial.println(""); delay(SERIAL_DELAY); } // end output response } //***CONTINUOUS SERIAL PRINT OUT COMMAND RESPONSE WITH MULTIPLE PARAMETERS FUNCTION***// // Function : printResponseContinuous // // Description: Serial Print output of the continuous responses from APIs // // Parameters : responseStatus : String : The response to the API call (RAW,LOG) // responseNumber : byte : 0,1,2 (Different meanings depending on the responseStatus) // responseParameterSize : byte : The size of the array which holds output response parameters // responseParameterDelimiter : char array : The delimiter used to separate multiple response parameters // responseParameter : int array : The response parameters printed as output // // Return : void //************************************************************************************// void printResponseContinuous(String responseStatus, byte responseNumber, byte responseParameterSize, char responseParameterDelimiter, int responseParameter[]) { char tempParameterDelimiter[1]; (isValidDelimiter(responseParameterDelimiter)) ? tempParameterDelimiter[0] = {responseParameterDelimiter} : tempParameterDelimiter[0] = {'\0'}; Serial.print(responseStatus); Serial.print(","); Serial.print(responseNumber); Serial.print(":"); for (byte parameterIndex = 0; parameterIndex < responseParameterSize; parameterIndex++) { Serial.print(responseParameter[parameterIndex]); if (parameterIndex < (responseParameterSize - 1)) { Serial.print(tempParameterDelimiter[0]); } } Serial.println(""); } //***PERFORM COMMAND FUNCTION TO CHANGE SETTINGS USING SOFTWARE***// // Function : performCommand // // Description: This function takes processes an input string from the serial and calls the // corresponding API function, or outputs an error. // // Parameters : inputString : String : The input command as a string. // // Return : void //*********************************// void performCommand(String inputString) { int inputCommandIndex = inputString.indexOf(':'); // Extract command string from input string String inputCommandString = inputString.substring(0, inputCommandIndex); // Extract parameter string from input string String inputParameterString = inputString.substring(inputCommandIndex + 1); // Determine total number of API commands byte totalCommandNumber = sizeof(apiFunction) / sizeof(apiFunction[0]); // Iterate through each API command for (byte apiIndex = 0; apiIndex < totalCommandNumber; apiIndex++) { // Test if input command string matches API command and input parameter string matches API parameter string if ( inputCommandString == apiFunction[apiIndex]._command && ((int)inputParameterString.toInt() == apiFunction[apiIndex]._parameter || apiFunction[apiIndex]._parameter == 1 || apiFunction[apiIndex]._parameter == 2 )) { // Matching Command String found if ( isStrNumber(inputParameterString)) // Check if parameter is valid { // Valid Parameter // Handle parameters that are an array as a special case. if (apiFunction[apiIndex]._parameter == 2) // 2 denotes an array parameter { int inputParameterArray[inputParameterString.length() + 1]; for (unsigned int arrayIndex = 0; arrayIndex < inputParameterString.length(); arrayIndex++) { inputParameterArray[arrayIndex] = inputParameterString.charAt(arrayIndex) - '0'; } // Call matching API function with input parameter array apiFunction[apiIndex]._function(true, true, inputParameterArray); //delay(5); } else { int tempParameterArray[1] = {(int)inputParameterString.toInt()}; // Call matching API function with input parameter string apiFunction[apiIndex]._function(true, true, tempParameterArray); //delay(5); } } else { // Invalid input parameter // Output error message printResponseSingle(true, true, false, 2, inputString, false, 0); } break; } else if (apiIndex == (totalCommandNumber - 1)) { // Command doesn’t exist - Output error message printResponseSingle(true, true, false, 1, inputString, false, 0); break; } } //end iterate through API functions } //***LED ON FUNCTION***// // Function : ledOn // // Description: This function is used to turn LEDs on. // // Parameters : ledNumber : int : The led number (1: Turn green on , 2: Turn red on). // // Return : void //*********************************// void ledOn(int ledNumber) { switch (ledNumber) { case 1: { // Turn GREEN LED on digitalWrite(LED_GREEN_PIN, HIGH); // delay(5); digitalWrite(LED_RED_PIN, LOW); break; } case 2: { // Turn RED LED on digitalWrite(LED_RED_PIN, HIGH); // delay(5); digitalWrite(LED_GREEN_PIN, LOW); break; } } } //***LED CLEAR FUNCTION***// // Function : ledClear // // Description: This function is used to turns both LEDs off. // // Parameters : void // // Return : void //*********************************// void ledClear(void) { digitalWrite(LED_GREEN_PIN, LOW); digitalWrite(LED_RED_PIN, LOW); } //***LED BLINK FUNCTION***// // Function : ledBlink // // Description: This function blinks the LEDs. // // Parameters : numBlinks : int : The number of LED blinks. // delayBlinks : int : The delay for each LED blink. // ledNumber : int : The led number (1: Flash green, 2: Flash red, 3: Alternate). // // Return : void //*********************************// void ledBlink(int numBlinks, int delayBlinks, int ledNumber) { switch (ledNumber) { case 1: { // Flash green for (byte i = 0; i < numBlinks; i++) { digitalWrite(LED_GREEN_PIN, HIGH); delay(delayBlinks); digitalWrite(LED_GREEN_PIN, LOW); delay(delayBlinks); } break; } case 2: { // Flash red for (byte i = 0; i < numBlinks; i++) { digitalWrite(LED_RED_PIN, HIGH); delay(delayBlinks); digitalWrite(LED_RED_PIN, LOW); delay(delayBlinks); } break; } case 3: { // Alternate flashing red and green for (byte i = 0; i < numBlinks; i++) { digitalWrite(LED_GREEN_PIN, HIGH); delay(delayBlinks); digitalWrite(LED_GREEN_PIN, LOW); delay(delayBlinks); digitalWrite(LED_RED_PIN, HIGH); delay(delayBlinks); digitalWrite(LED_RED_PIN, LOW); delay(delayBlinks); } break; } } } //***PUSH BUTTON SPEED HANDLER FUNCTION***// // Function : pushButtonHandler // // Description: This function handles the push button actions. Pressed individually, these change sensitivity and // pressed together they initiate the joystick calibration. // // Parameters : void // // Return : void //*********************************// void pushButtonHandler() { if (digitalRead(BUTTON_UP_PIN) == LOW) { delay(250); if (digitalRead(BUTTON_DOWN_PIN) == LOW){ setJoystickCalibration(true, false); // Call joystick calibration if both push button up and down are pressed g_buttonPreviousState[0] = HIGH; g_buttonPreviousState[1] = HIGH; } else if (g_buttonPreviousState[0] == HIGH && digitalRead(BUTTON_DOWN_PIN) == HIGH) { // Up button pushed g_buttonTimer[0] = millis(); g_buttonPreviousState[0] = LOW; g_buttonPreviousState[1] = HIGH; } } else if (digitalRead(BUTTON_UP_PIN) == HIGH) { if (g_buttonPreviousState[0] == LOW && digitalRead(BUTTON_DOWN_PIN) == HIGH && g_buttonPreviousState[1] == HIGH && (millis() - g_buttonTimer[0] >= BUTTON_LONG_PRESS_TIME)) { // Up button was released after 2 seconds ( button up long press) setButtonMode(true,false,BUTTON_ANALOG_MODE); // Set Button Analog Mode ledBlink(2, 500, 3); // Blink Red and Green twice g_buttonPreviousState[0] = HIGH; g_buttonPreviousState[1] = HIGH; } else if (g_buttonPreviousState[0] == LOW && digitalRead(BUTTON_DOWN_PIN) == HIGH && g_buttonPreviousState[1] == HIGH && (millis() - g_buttonTimer[0] < BUTTON_LONG_PRESS_TIME)) { // Up button was released before 2 seconds ( button up short press) increaseJoystickSensitivity(true, false); // Call increase joystick sensitivity function if push button up is pressed g_buttonPreviousState[0] = HIGH; g_buttonPreviousState[1] = HIGH; } } if (digitalRead(BUTTON_DOWN_PIN) == LOW) { delay(250); if (digitalRead(BUTTON_UP_PIN) == LOW){ setJoystickCalibration(true, false); // Call joystick calibration if both push button up and down are pressed g_buttonPreviousState[0] = HIGH; g_buttonPreviousState[1] = HIGH; } else if (g_buttonPreviousState[1] == HIGH && digitalRead(BUTTON_UP_PIN) == HIGH) { // Down button pushed g_buttonTimer[1] = millis(); g_buttonPreviousState[0] = HIGH; g_buttonPreviousState[1] = LOW; } } else if (digitalRead(BUTTON_DOWN_PIN) == HIGH) { if (g_buttonPreviousState[1] == LOW && digitalRead(BUTTON_UP_PIN) == HIGH && g_buttonPreviousState[0] == HIGH && (millis() - g_buttonTimer[1] >= BUTTON_LONG_PRESS_TIME)) { // Down button was released after 2 seconds ( button down long press) setButtonMode(true,false,BUTTON_DIGITAL_MODE); // Set Button Digital Mode ledBlink(1, 500, 3); // Blink Red and Green once g_buttonPreviousState[0] = HIGH; g_buttonPreviousState[1] = HIGH; } else if (g_buttonPreviousState[1] == LOW && digitalRead(BUTTON_UP_PIN) == HIGH && g_buttonPreviousState[0] == HIGH && (millis() - g_buttonTimer[1] < BUTTON_LONG_PRESS_TIME)) { // Down button was released before 2 seconds ( button down short press) decreaseJoystickSensitivity(true, false); // Call decrease joystick sensitivity function if push button up is pressed g_buttonPreviousState[0] = HIGH; g_buttonPreviousState[1] = HIGH; } } } //***SIP AND PUFF RAW ACTION HANDLER FUNCTION***// // Function : sipAndPuffRawHandler // // Description: This function handles the sip and puff raw actions. // // Parameters : void // // Return : int : sip and puff raw action numbers //*********************************// int sipAndPuffRawHandler() { int currentAction = 0; // Read pressure sensor for sip and puff functions g_joystickPressure = readPressure(); // [ADC steps] //Measure the pressure value and compare the result with puff pressure Thresholds if (g_joystickPressure < g_puffThreshold) { delay(5); currentAction = 1; } //Measure the pressure value and compare the result with sip pressure Thresholds if (g_joystickPressure > g_sipThreshold) { delay(5); currentAction = 2; } return currentAction; } //***SIP AND PUFF ACTION HANDLER FUNCTION***// // Function : sipAndPuffHandler // // Description: This function handles the sip and puff actions using input button mapping. // // Parameters : void // // Return : void //*********************************// void sipAndPuffHandler() { // Read pressure sensor for sip and puff functions g_joystickPressure = readPressure(); // [ADC steps] // Puff handling: check if the pressure is under puff pressure threshold and measure how long until it is released if (g_joystickPressure < g_puffThreshold) { //Puff detected if(g_buttonMode == 1) { while (g_joystickPressure < g_puffThreshold) // Continue measuring pressure until puff stops { g_joystickPressure = readPressure(); g_puffCount++; // Count number of cycles pressure value has been under puff pressure threshold if (g_puffCount == PUFF_COUNT_THRESHOLD_MED) // When first count threshold is reached, turn on light { ledClear(); // Turn off LEDs } else if (g_puffCount == PUFF_COUNT_THRESHOLD_LONG) // When second count threshold is reached, turn off light { ledClear(); // Turn off LEDs } delay(PRESSURE_HANDLER_DELAY); } // end puff measurement // USB puff actions if (g_puffCount < PUFF_COUNT_THRESHOLD_MED) { performButtonAction(g_actionButton[0]); // Perform Short puff action } else if (g_puffCount >= PUFF_COUNT_THRESHOLD_MED && g_puffCount < PUFF_COUNT_THRESHOLD_LONG) { performButtonAction(g_actionButton[2]); // Perform long puff action } else if (g_puffCount >= PUFF_COUNT_THRESHOLD_LONG) { performButtonAction(g_actionButton[4]); // Perform very long puff action } g_puffCount = 0; //Reset puff counter } else if(g_buttonMode == 2) { joystickButtonPress(g_actionButton[0]); } } // Sip handling: check if the pressure is above sip pressure threshold and measure how long until it is released if (g_joystickPressure > g_sipThreshold) { // Sip detected if(g_buttonMode == 1) { while (g_joystickPressure > g_sipThreshold) { // Continue measuring pressure until sip stops g_joystickPressure = readPressure(); g_sipCount++; // Count how long the pressure value has been above sip pressure threshold if (g_sipCount == SIP_COUNT_THRESHOLD_MED) // When first count threshold is reached, turn on light { ledOn(1); //Turn on green led } else if (g_sipCount == SIP_COUNT_THRESHOLD_LONG) // When second count threshold is reached, turn off light { ledClear(); // Turn off LEDs. } delay(PRESSURE_HANDLER_DELAY); } //USB Sip actions if (g_sipCount < SIP_COUNT_THRESHOLD_MED) { performButtonAction(g_actionButton[1]); // Perform short sip action } else if (g_sipCount >= SIP_COUNT_THRESHOLD_MED && g_sipCount < SIP_COUNT_THRESHOLD_LONG) { performButtonAction(g_actionButton[3]); // Perform long sip action } else if (g_sipCount >= SIP_COUNT_THRESHOLD_LONG) { //Perform seconday function if sip counter value is more than 750 ( 5 second Long Sip ) performButtonAction(g_actionButton[5]); // Perform very long sip action } g_sipCount = 0; // Reset sip counter } // end sip handling else if(g_buttonMode == 2) { joystickButtonPress(g_actionButton[1]); } } if (g_joystickPressure <= g_sipThreshold && g_joystickPressure >= g_puffThreshold && g_buttonMode == 2) { //Release buttons in analog trigger button mode joystickButtonRelease(g_actionButton[0]); joystickButtonRelease(g_actionButton[1]); } } //***PERFORM BUTTON ACTION FUNCTION**// // Function : performButtonAction // // Description: This function perform mapped output actions (e.g. left click) based on input action (e.g. short puff) // // Parameters : outputAction : byte : The output action number used to map sip and puff inputs. // // Return : void //*********************************// void performButtonAction(byte outputAction) { switch (outputAction) { case OUTPUT_NOTHING: { // Perform no action break; } case OUTPUT_BUTTON_ONE: case OUTPUT_BUTTON_TWO: case OUTPUT_BUTTON_THREE: case OUTPUT_BUTTON_FOUR: case OUTPUT_BUTTON_FIVE: case OUTPUT_BUTTON_SIX: { // Button Click: Perform joystick button click action joystickButtonClick(outputAction); delay(5); break; } case OUTPUT_JOYSTICK_HOME_RESET: { // Joystick Initialization: Perform joystick manual home initialization to reset default value of FSR's ledClear(); ledBlink(4, 350, 3); setJoystickInitialization(true, false); delay(5); break; } case OUTPUT_JOYSTICK_CALIBRATION: { // Joystick Calibration: Perform joystick Calibration to reset default value of FSR's // Default: if puff counter value is more than 750 ( 5 second Long Puff ) setJoystickCalibration(true, false); delay(5); break; } }// end switch } //***JOYSTICK BUTTON CLICK FUNCTION***// // Function : joystickButtonClick // // Description: This function performs joystick button click action. // // Parameters : byte : buttonNumber : The button number to be clicked. // // Return : void //****************************************// void joystickButtonClick(byte buttonNumber) { byte buttonIndex = buttonNumber - 1; ledClear(); if (!g_lastButtonState[buttonIndex]) { Joystick.pressButton(buttonIndex); delay(JOYSTICK_BUTTON_DELAY); Joystick.releaseButton(buttonIndex); delay(50); g_lastButtonState[buttonIndex] = 0; } } //***JOYSTICK BUTTON PRESS FUNCTION***// // Function : joystickButtonPress // // Description: This function performs joystick button press action. // // Parameters : byte : buttonNumber : The button number to be pressed. // // Return : void //****************************************// void joystickButtonPress(byte buttonNumber) { byte buttonIndex = buttonNumber - 1; ledClear(); Joystick.pressButton(buttonIndex); g_lastButtonState[buttonIndex] = 1; } //***JOYSTICK BUTTON RELEASE FUNCTION***// // Function : joystickButtonRelease // // Description: This function performs joystick button release action. // // Parameters : byte : buttonNumber : The button number to be released. // // Return : void //****************************************// void joystickButtonRelease(byte buttonNumber) { byte buttonIndex = buttonNumber - 1; ledClear(); Joystick.releaseButton(buttonIndex); g_lastButtonState[buttonIndex] = 0; }