Advertisement
Guest User

OpenBarbell-ESP32

a guest
Jul 4th, 2025
33
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 54.66 KB | Source Code | 0 0
  1. // Fix rest time to be last rest time
  2. // Fix go back at delete prompt
  3.  
  4. #include <SPI.h>
  5. #include <Wire.h>
  6. #include <Arduino.h>
  7. // #include <MAX1704.h> // Battery Management
  8. #include <Adafruit_GFX.h>
  9. #include <Adafruit_SSD1306.h>
  10. #include <BLEDevice.h>
  11. #include <BLEServer.h>
  12. #include <BLEUtils.h>
  13. #include <BLE2902.h>
  14. #include <Filters.h>
  15. #include "FastLED.h"
  16. #include <pgmspace.h>
  17. #include <string>
  18.  
  19. ////////////////////////
  20. // #define DEBUG     1
  21. ////////////////////////
  22.  
  23. ////-------------------------------------------------------------------------
  24. //////////            0. Preprocessor Definitions            ////////////
  25. ////-------------------------------------------------------------------------
  26.  
  27. // OLED Definitions
  28. #define SCREEN_WIDTH 128
  29. #define SCREEN_HEIGHT 64
  30. #define SDA_PIN 21  // Change to your actual SDA pin
  31. #define SCL_PIN 22  // Change to your actual SCL pin
  32. #define OLED_RESET -1
  33. // Adafruit_SSD1306 display(OLED_RESET);
  34. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
  35.  
  36. // Filter Definitions
  37. #define max_tick_time_allowable_init 130000
  38. #define precisionCounter_start 5
  39. #define MAXVEL 10
  40.  
  41. // LED Definitions
  42. #define NUM_LEDS 1
  43. #define DATA_PIN 2
  44. #define LOW_POWER 1
  45. #define BRIGHTNESS 20
  46. enum color {RED, GREEN, BLK, WHT};
  47.  
  48. // Device Info
  49. // const char *device_name = "RepOne 1YHy2";
  50. // const char *device_name = "OpenBarbell - ESP32";
  51. const char *device_name = "OB ESP32";
  52. // const long ticLength = 2718;
  53. const long ticLength = 2950;
  54. const int unit_number = 4747;
  55. color COLOR = RED;
  56.  
  57. // Version Info
  58. float CODE_VERSION = 3.1;
  59.  
  60. // TestBed Section - Do Not Modify
  61. const bool testbed_readouts = 0;
  62.  
  63. //-------------------------------------------------------------------------
  64. //////////                  1. Variables                     ////////////
  65. //-------------------------------------------------------------------------
  66.  
  67. // BT Setup
  68. boolean bluetoothOn = false;
  69. boolean bluetoothStartNextLoop = false;
  70. float repPerformance[] = {0.0, 1.0, 2.0, 3.0, 4.0, 5.0};
  71. bool BTRefresh = false;
  72. bool BTisconnected = 0;
  73.  
  74. // LED Setup
  75. CRGB leds[1];
  76. byte r, g, b, LVL = BRIGHTNESS, userColor = 0;
  77.  
  78. // Pin Definitions
  79. const int pin_buttonRight = 18;
  80. const int pin_buttonLeft = 15;
  81. // const int pin_encoder_dir = 4;
  82. const int pin_encoder_tach = 5;
  83.  
  84. void IRAM_ATTR encoderState();
  85.  
  86. // State Initializations
  87. uint16_t charge = 100;
  88. volatile int state = LOW;
  89. // state flips on startup, so we need to put the temp value at HIGH so we don't run through the
  90. // code one time at startup before getting an actual tic reading
  91. volatile int currentStateTemp = HIGH;
  92. volatile bool goingUpward = 0;
  93. volatile bool isGoingUpwardLast = 0;
  94. long avgVelocity = 0;
  95. unsigned long starttime = 0;
  96. bool overrun = false;
  97. bool isFlipped = false;
  98. bool flipPowerOlyScreen = false; // 0 = Power screen, 1 = Oly screen
  99. bool sendData = false;
  100. bool _initialized = false;
  101. bool flippedDirection = false;
  102. bool normalDirection = false;
  103. bool dataCOMPRESSION_enabled = 1; // THIS MUST BE ENABLED (1) FOR PRODUCTION CODE - ONLY DISABLE (0) FOR TESTING PURPOSES!
  104. bool full_data_logging_enabled = 0;
  105.  
  106. // Rep Variable Initializations
  107. uint16_t rep = 0;
  108. uint16_t repDone = 0;
  109. uint16_t repDoneLast = 0;
  110. uint16_t repDisplay = 2;
  111. uint16_t repDisplayLast = 0;
  112. uint16_t peak_vel_at = 0;
  113. long displacement = 0;
  114. int minRepThreshold = 150000; // in micrometers - 150000 micrometers = 150 mm = ~5.9 inches
  115.  
  116. // Time Initializations
  117. unsigned long tic_time = 0;
  118. unsigned long tic_timestamp = 0;
  119. unsigned long tic_timestampLast = 0;
  120. unsigned long tic_timestampLast2 = 0;
  121. unsigned long tic_timestamp_last = 0;
  122. unsigned long minDT = 1000000;
  123. unsigned long blink_override_threshold = 5000000;
  124. unsigned long total_time = 0;
  125. unsigned long displayTime = 0;
  126. unsigned long batteryTime = 0;
  127. unsigned long minTimer = 0;
  128. unsigned long minTimer2 = 0;
  129. unsigned long twoSecTimer2 = 0;
  130. unsigned long oneMinute = 60000;
  131. unsigned long twoSec = 2000;
  132. unsigned long ticDiff = 0;
  133. unsigned long ticDiffFiltered = 0;
  134. unsigned long backlightTime = 10000;
  135. unsigned long last_avg = 0;
  136. unsigned long last_press = 0;
  137. uint16_t restTime = 0;
  138.  
  139. // Tick Counter Initialization
  140. const int myDTCounter_size = 1100; // 1200 Dts will give 1200*~2.68 mm = 3.2 m = 10.5 ft
  141. uint16_t myDTs[myDTCounter_size] = {0};
  142. uint16_t myDTCounter = 0;
  143. // uint16_t FILTER_out[myDTCounter_size] = {0};
  144.  
  145. // Rep Array Initializations
  146. const int repArrayCount = 100;
  147. float repArray[repArrayCount] = {0.0};
  148. float peakVelocity[repArrayCount] = {0.0};
  149. uint16_t dispArray[repArrayCount] = {0};
  150. float timeArray[repArrayCount] = {0.0};
  151. byte peakVelLocation[repArrayCount] = {0};
  152. byte rest[repArrayCount] = {0};
  153.  
  154. // Button Action Setup
  155. bool doubleclick = false;
  156. uint16_t buttonstateR = 0;
  157. uint16_t buttonstateL = 0;
  158. int buttonstate = 0;
  159. uint16_t buttonstateRtemp = 0;
  160. uint16_t buttonstateLtemp = 0;
  161. unsigned long rightHold = 0;
  162. unsigned long leftHold = 0;
  163. uint16_t rightHoldActionTime = 1500;
  164. uint16_t leftHoldActionTime = 1500;
  165. uint16_t bothHoldActionTime = 3000;
  166. uint16_t singleHoldActionTime = 3000;
  167. uint16_t replast = 0;
  168. boolean backlightFlag = 1;
  169. boolean RbuttonDepressed = 0;
  170. boolean LbuttonDepressed = 0;
  171. bool buttonRightLongPress = 0;
  172. bool buttonLeftLongPress = 0;
  173. bool bothbuttonlong = 0;
  174. const int buttonholdtimer = 10; // delay time
  175. int counter_buttonRighthold = 0;
  176. int counter_buttonLefthold = 0;
  177. const int threshold_buttonhold = 100; // cycles of buttonholdtimer to cross threshold
  178. bool accomplishedDoubleHold = false;
  179. bool accomplishedSingleHold = false;
  180.  
  181. // Accurate Velocity Variables
  182. float currentInstVel = 0.0;
  183. float lastInstVel = 0.0;
  184. float peakVelTemp = 0.0;
  185.  
  186. // Interrupt Timer
  187. static unsigned long last_interrupt_time = 0;
  188. static unsigned long last_interrupt_time2 = 0;
  189. static unsigned long last_tic_time = 0;
  190.  
  191. // Start Message
  192. float startMessage[1] = {-3456.0};
  193.  
  194. // Moving Average Variables
  195. int Filtration_Output = 1;
  196. const int moving_average_size = 16;
  197. int moving_average_offset = 3;
  198. unsigned long moving_average_holder = 0;
  199. float peakAccel = 0;
  200. float peakAccelHolder = 0;
  201. unsigned long moving_average_vector[moving_average_size] = {15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000, 15000};
  202. float one_over_moving_average_size = 1 / (float)moving_average_size;
  203. float average_tick_length = 2755.95; // ((3.1419 + 2.37) / 2) * 1000 for micrometers
  204. int ticDiffprecision = 10;
  205.  
  206. // Filter Variables
  207. float testFrequency = 10;
  208. FilterOnePole filterOneLowpass( LOWPASS, testFrequency );
  209. uint16_t precisionCounter = precisionCounter_start;
  210. volatile unsigned int counter_simplelengthbytic = 0; // This is a simple counter that is called to count how many times we enter the interrupt
  211.  
  212. unsigned long micros_holder = 0; // This is a temporary holder used so we don't have to keep calling micros()
  213. unsigned long max_tick_time_allowable = max_tick_time_allowable_init; // max_tick_time_allowable is a variable that is used to determine ifthe the rep "started" but really it's just pausing - see above for math used to derive number6
  214. unsigned long time_waiting = 0; // Once we determine that the user is pausing during a rep we start to increment a waiting timer to subtract from the overall time
  215.  
  216. /*
  217.   - "Min" detectable speed = .01 m/s = 10 mm/s
  218.   - "Min" tick length = ~2.6 mm/
  219.   - "Min" ticks/second = (min detectable speed)/(min tick length) = (10 mm/s)/(2.6 mm/tick) = ~3.8462 ticks/second
  220.   - "Max" time between ticks = (1 tick)/(min ticks/second)=(1)/(~3.8462 ticks/second) = .26 sec = 260000 microseconds = max_tick_time_allowable
  221. */
  222.  
  223. // Fuel Gauge Setup
  224. // MAX1704 fuelGauge;
  225.  
  226. // Add ESP32 BLE variables
  227. BLEServer* pServer = NULL;
  228. BLECharacteristic* pCharacteristic = NULL;
  229. bool deviceConnected = false;
  230. bool oldDeviceConnected = false;
  231.  
  232. // Define UUIDs for BLE service and characteristic
  233. #define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
  234. #define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
  235.  
  236. // Forward declare the callback classes before they're used
  237. class MyServerCallbacks;
  238. class MyCharacteristicCallbacks;
  239.  
  240. // Replace RFduino delay with standard delay
  241. #define SECONDS(x) ((x) * 1000)
  242.  
  243. // Add function declaration at the top of the file (after includes)
  244. void RFduinoBLE_onReceive(char *data, int len);
  245. void RFduinoBLE_onConnect();
  246. void RFduinoBLE_onDisconnect();
  247.  
  248. // Move the callback class definitions to before they're used (place this before setup())
  249. class MyServerCallbacks: public BLEServerCallbacks {
  250.   void onConnect(BLEServer* pServer) {
  251.     deviceConnected = true;
  252.     // Handle connection
  253.     r = 0;
  254.     g = 0;
  255.     b = 5;
  256.     BTRefresh = true;
  257.     BTisconnected = 1;
  258.   };
  259.  
  260.   void onDisconnect(BLEServer* pServer) {
  261.     deviceConnected = false;
  262.     // Handle disconnection
  263.     BTisconnected = 0;
  264.     if (userColor > 0) {
  265.       r = userColor / 50;
  266.       g = (userColor % 100) / 10;
  267.       b = (userColor % 10);
  268.     } else {
  269.       if (COLOR == RED) {
  270.         r = 5;
  271.         g = 0;
  272.         b = 0;
  273.       } else if (COLOR == GREEN) {
  274.         r = 0;
  275.         g = 5;
  276.         b = 0;
  277.       } else if (COLOR == BLK) {
  278.         r = 5;
  279.         g = 0;
  280.         b = 5;
  281.       } else {
  282.         r = 5;
  283.         g = 5;
  284.         b = 5;
  285.       }
  286.     }
  287.   }
  288. };
  289.  
  290. class MyCharacteristicCallbacks: public BLECharacteristicCallbacks {
  291.   void onWrite(BLECharacteristic *pCharacteristic) {
  292.     // Get the raw data
  293.     uint8_t* data = pCharacteristic->getData();
  294.     size_t len = pCharacteristic->getLength();
  295.  
  296.     if (len > 0) {
  297.       // Call our RFduinoBLE_onReceive function with the raw data
  298.       RFduinoBLE_onReceive((char*)data, len);
  299.     }
  300.   }
  301. };
  302.  
  303. //-------------------------------------------------------------------------
  304. //////////                     2. Setup                      ////////////
  305. //-------------------------------------------------------------------------
  306. // Initializations of all defined libraries that require function logic //
  307. //-------------------------------------------------------------------------
  308.  
  309. // void setup() {
  310. //   // LED Color Configuration
  311. //   if (COLOR == RED) {
  312. //     r = 5;
  313. //     g = 0;
  314. //     b = 0;
  315. //     userColor = 200;
  316. //   } else if (COLOR == GREEN) {
  317. //     r = 0;
  318. //     g = 5;
  319. //     b = 0;
  320. //     userColor = 50;
  321. //   } else if (COLOR == BLK) {
  322. //     r = 5;
  323. //     g = 0;
  324. //     b = 5;
  325. //     userColor = 205;
  326. //   } else {
  327. //     r = 5;
  328. //     g = 5;
  329. //     b = 5;
  330. //     userColor = 255;
  331. //   }
  332. //   FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, 1);
  333. //
  334. //   initializeBluetooth();
  335. //
  336. //   // I2C + OLED Begin()
  337. //   Wire.begin();
  338. //   delay(200); // display needs about 100ms to initialize the IC
  339. //   display.begin(SSD1306_SWITCHCAPVCC, 0x3C); // initialize with the I2C addr 0x3C (for the 128x64)
  340. //   // Pin Configuration
  341. //   pinMode(pin_buttonRight, INPUT_PULLDOWN);
  342. //   pinMode(pin_buttonLeft, INPUT_PULLDOWN);
  343. //   // pinMode(DATA_PIN, INPUT_PULLDOWN);
  344. //   pinMode(pin_encoder_tach, INPUT);
  345. //   pinMode(pin_encoder_dir, INPUT);
  346. //
  347. //   // Interrupt Callback Definition
  348. //   attachInterrupt(digitalPinToInterrupt(pin_encoder_tach), encoderState, RISING);
  349. //
  350. //   // Welcome Screen - Logo + Device Information
  351. //   display.setTextSize(2);
  352. //   display.setTextColor(WHITE);
  353. //   display.setCursor(72, 9);
  354. //   display.println("OBV3");
  355. //   display.setTextSize(1);
  356. //   display.setCursor(70, 36);
  357. //   display.print("Unit ");
  358. //   display.print(unit_number);
  359. //
  360. //   display.setCursor(70, 46);
  361. //   display.print("Rev ");
  362. //   display.print(CODE_VERSION);
  363. //   display.display();
  364. //
  365. //   leds[0].setRGB( 0, 0, 0);
  366. //   FastLED.show();
  367. //
  368. //   // LED Boot Animation
  369. //   #ifndef DEBUG
  370. //   int R,G,B;
  371. //     for (int foo = 0;foo < 1800; foo++)
  372. //     {
  373. //       R = 5 + .95 * cubicwave8(foo);
  374. //       G = 5 + .95 * cubicwave8(foo / 2);
  375. //       B = 5 + .95 * cubicwave8(foo / 3);
  376. //       leds[0].setRGB(R / 8, G / 8, B / 8);
  377. //       FastLED.show();
  378. //       delay(1);
  379. //     }
  380. //   #endif
  381. //   leds[0].setRGB( 0, 0, 0);
  382. //   FastLED.show();
  383. //
  384. //   // Initialize Rest Time
  385. //   rest[1] = 0;
  386. //
  387. //   // Initial Charge Check
  388. //   // Low brightness addition       *****
  389. //   charge = 100; // fuelGauge.stateOfCharge();
  390. //   if (charge > 100) {
  391. //     charge = 100;
  392. //   } else if (charge <= 20) {
  393. //     LVL = LOW_POWER;
  394. //   } else if (charge <= 0) {
  395. //     charge = 1;
  396. //   }
  397. // }
  398.  
  399. void setup() {
  400.   if (COLOR == RED) {
  401.     r = 5;
  402.     g = 0;
  403.     b = 0;
  404.     userColor = 200;
  405.   } else if (COLOR == GREEN) {
  406.     r = 0;
  407.     g = 5;
  408.     b = 0;
  409.     userColor = 50;
  410.   } else if (COLOR == BLK) {
  411.     r = 5;
  412.     g = 0;
  413.     b = 5;
  414.     userColor = 205;
  415.   } else {
  416.     r = 5;
  417.     g = 5;
  418.     b = 5;
  419.     userColor = 255;
  420.   }
  421.   FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, 1);
  422.  
  423.   initializeBluetooth();
  424.  
  425.   Wire.begin(SDA_PIN, SCL_PIN);
  426.   delay(200);
  427.  
  428.   display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  429.  
  430.   display.clearDisplay();
  431.   display.display();
  432.   delay(100);
  433.  
  434.   pinMode(pin_buttonRight, INPUT_PULLUP);
  435.   pinMode(pin_buttonLeft, INPUT_PULLUP);
  436.   pinMode(pin_encoder_tach, INPUT);
  437.   // pinMode(pin_encoder_dir, INPUT_PULLUP);
  438.  
  439.   attachInterrupt(digitalPinToInterrupt(pin_encoder_tach), encoderState, RISING);
  440.  
  441.   display.clearDisplay();
  442.   display.setTextSize(2);
  443.   display.setTextColor(WHITE);
  444.   display.setCursor(72, 9);
  445.   display.println("OBV3");
  446.   display.setTextSize(1);
  447.   display.setCursor(70, 36);
  448.   display.print("Unit ");
  449.   display.print(unit_number);
  450.   display.setCursor(70, 46);
  451.   display.print("Rev ");
  452.   display.print(CODE_VERSION);
  453.   display.display();
  454.  
  455.   // LED off initially
  456.   leds[0].setRGB(0, 0, 0);
  457.   FastLED.show();
  458.  
  459.   #ifndef DEBUG
  460.   int R,G,B;
  461.   for (int foo = 0; foo < 1800; foo++) {
  462.     R = 5 + .95 * cubicwave8(foo);
  463.     G = 5 + .95 * cubicwave8(foo / 2);
  464.     B = 5 + .95 * cubicwave8(foo / 3);
  465.     leds[0].setRGB(R / 8, G / 8, B / 8);
  466.     FastLED.show();
  467.     delay(1);
  468.   }
  469.   #endif
  470.  
  471.   leds[0].setRGB(0, 0, 0);
  472.   FastLED.show();
  473.  
  474.   rest[1] = 0;
  475.  
  476.   charge = 100;
  477.   // if (charge <= 20) {
  478.   //   LVL = LOW_POWER;
  479.   // }
  480. }
  481.  
  482. //-------------------------------------------------------------------------
  483. //////////                     3. Main Loop                    ////////////
  484. //-------------------------------------------------------------------------
  485. //      Main logic loop for OpenBarbell V3 - Use CTRL + F to find fcns   //
  486. //-------------------------------------------------------------------------
  487.  
  488. void loop() {
  489.   // directionCalc();                // 4. Direction Flag
  490.   calcRep(goingUpward, state);    // 13. Rep Calculation Algorithm
  491.   buttonStateCalc();              // 14. Button Press State Configuration )
  492.   minuteTimer();                  // 7. Minute Timer
  493.   // displayOffTimer();              // 9. Display Timeout
  494.   // LEDBlink();                     // 8. LED Updater
  495. }
  496.  
  497. //-------------------------------------------------------------------------
  498. //////////                  4. Direction Flag                  ////////////
  499. //-------------------------------------------------------------------------
  500. //         Determines the current direction the spindle is spinning      //
  501. //-------------------------------------------------------------------------
  502.  
  503. // void directionCalc() {
  504. //   // define flipped direction (direction when you use your device upside-down)
  505. //   flippedDirection = !digitalRead(pin_encoder_dir);
  506. //   normalDirection = (!_initialized) ? (0) : (!flippedDirection);
  507. //   // normal direction is usually directly read from the encoder, but the encoder initializes giving us the 'up'
  508. //   // direction (pin value zero). We need the intial reading to tell us 'down', because that's what it always is
  509. //   // when the string is retracted into the device. So if we haven't read any tics yet, set normalDirection to zero
  510. //   goingUpward = (isFlipped) ? (flippedDirection) : (normalDirection);
  511. // }
  512.  
  513. //-------------------------------------------------------------------------
  514. //////////                   5. Invert Mode                    ////////////
  515. //-------------------------------------------------------------------------
  516. //                   Inverts the screen for top-down use                 //
  517. //-------------------------------------------------------------------------
  518.  
  519. // void invertMode() {
  520. //   isFlipped = !isFlipped;
  521. //   accomplishedDoubleHold = true;
  522. //   display.ssd1306_command(SSD1306_DISPLAYON);
  523. //   display.clearDisplay();
  524. //   display.invertDisplay(isFlipped);
  525. //   display.setTextSize(3);
  526. //   display.setCursor(0, 0);
  527. //
  528. //   if (isFlipped) {
  529. //     display.print("INVERT");
  530. //     display.setCursor(0, 32);
  531. //     display.setTextSize(2);
  532. //     display.print("MODE ON");
  533. //   } else {
  534. //     display.print("INVERT");
  535. //     display.setCursor(0, 32);
  536. //     display.setTextSize(2);
  537. //     display.print("MODE OFF");
  538. //   }
  539. //
  540. //   display.display();
  541. //   delay(2000);
  542. //
  543. //   if (repDone == 0) {
  544. //     repDisplayLast = 0;
  545. //   }
  546. //   repDisplay--;  // This is put in here so first rep isn't missed
  547. //   // repDisplay = repDone + 1;
  548. // }
  549.  
  550. //-------------------------------------------------------------------------
  551. //////////               6. Olympic Mode (Power)               ////////////
  552. //-------------------------------------------------------------------------
  553. //     Switches device operation from velocity to power tracking mode    //
  554. //-------------------------------------------------------------------------
  555.  
  556. void olyPowerMode() {
  557.   flipPowerOlyScreen = !flipPowerOlyScreen;
  558.   display.ssd1306_command(SSD1306_DISPLAYON);
  559.   display.clearDisplay();
  560.   display.setTextSize(3);
  561.   display.setCursor(0, 9);
  562.  
  563.   if (flipPowerOlyScreen) {
  564.     display.print("OLYMPIC");
  565.     display.setCursor(0, 32);
  566.     display.print("MODE");
  567.   } else {
  568.     display.print("POWER");
  569.     display.setCursor(0, 32);
  570.     display.print("MODE");
  571.   }
  572.  
  573.   display.display();
  574.   delay(2000);
  575.  
  576.   if (repDone == 0) {
  577.     repDisplayLast = 0;
  578.   }
  579.   repDisplay = repDone;
  580. }
  581.  
  582. //-------------------------------------------------------------------------
  583. //////////                  7. Minute Timer                    ////////////
  584. //-------------------------------------------------------------------------
  585. //        Tracks battery charge and rest time and updates display        //
  586. //-------------------------------------------------------------------------
  587.  
  588. void minuteTimer() { // Update minute timer so that display updates when rest at a minunte    *****
  589.   if (((millis() - minTimer) % oneMinute) < 20) { // Every minute (since last rep) with .02s accuracy
  590.     if ((millis() - minTimer2) > 30) { // If this function has been called within this minute, don't call it again
  591.       minTimer2 = millis();
  592.       restTime++; // Rest time accumulates
  593.       rest[repDone % repArrayCount] = restTime; // Rest time recorded for current rep
  594.       // charge = 100; // fuelGauge.stateOfCharge(); // Check battery status
  595.       //
  596.       // if (charge > 100) {
  597.       //   charge = 100;
  598.       // } else if (charge <= 0) {
  599.       //   charge = 1;
  600.       // }
  601.       //
  602.       // if (charge <= 20) { // Reduce LED brightness level when battery is under 20 percent
  603.       //   LVL = LOW_POWER;
  604.       // } else{
  605.       //   LVL = BRIGHTNESS;
  606.       // }
  607.  
  608.       if (!goingUpward || ((micros() - tic_timestamp) > blink_override_threshold)) {
  609.         systemTrayDisplay();
  610.         display.display();
  611.       }
  612.     }
  613.   }
  614. }
  615.  
  616. //-------------------------------------------------------------------------
  617. //////////                8. LED Updater                       ////////////
  618. //-------------------------------------------------------------------------
  619. //  Function to blink LED every XX seconds, ifthere's nothing going on   //
  620. //-------------------------------------------------------------------------
  621.  
  622. void LEDBlink() {
  623.   if (((millis() % twoSec) < 20) && ((!goingUpward) || ((micros() - tic_timestamp) > blink_override_threshold))) { // If it's been 2n seconds and the encoder's not in use
  624.     if ((millis() - twoSecTimer2) > 30) { // Makes sure the loop trips only once
  625.       twoSecTimer2 = millis();
  626.       leds[0].setRGB( LVL * r, LVL * g, LVL * b);
  627.       FastLED.show();
  628.       delay(20);
  629.       leds[0].setRGB( 0, 0, 0);
  630.       FastLED.show();
  631.     }
  632.   }
  633. }
  634.  
  635. //-------------------------------------------------------------------------
  636. //////////                 9. Display Timeout                  ////////////
  637. //-------------------------------------------------------------------------
  638. //     Periodically turns off LCD backlight to preserve battery life     //
  639. //-------------------------------------------------------------------------
  640.  
  641. void displayOffTimer() {
  642.   // if the displayed rep hasn't changed in a while, we don't need the backlight
  643.   if ((millis() - displayTime) > backlightTime) {
  644.     display.ssd1306_command(SSD1306_DISPLAYOFF);
  645.     backlightFlag = 0;
  646.   }
  647. }
  648.  
  649. //-------------------------------------------------------------------------
  650. //////////              10. Bluetooth Setup                    ////////////
  651. //-------------------------------------------------------------------------
  652. //                  Initializes Bluetooth Advertising                    //
  653. //-------------------------------------------------------------------------
  654.  
  655. void initializeBluetooth() {
  656.   // Create the BLE Device
  657.   BLEDevice::init(device_name);
  658.  
  659.   // Create the BLE Server
  660.   pServer = BLEDevice::createServer();
  661.   pServer->setCallbacks(new MyServerCallbacks());
  662.  
  663.   // Create the BLE Service
  664.   BLEService *pService = pServer->createService(SERVICE_UUID);
  665.  
  666.   // Create the BLE Characteristic
  667.   pCharacteristic = pService->createCharacteristic(
  668.                       CHARACTERISTIC_UUID,
  669.                       BLECharacteristic::PROPERTY_READ   |
  670.                       BLECharacteristic::PROPERTY_WRITE  |
  671.                       BLECharacteristic::PROPERTY_NOTIFY |
  672.                       BLECharacteristic::PROPERTY_INDICATE
  673.                     );
  674.  
  675.   pCharacteristic->addDescriptor(new BLE2902());
  676.   pCharacteristic->setCallbacks(new MyCharacteristicCallbacks());
  677.  
  678.   // Start the service
  679.   pService->start();
  680.  
  681.   // Start advertising
  682.   BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
  683.   pAdvertising->addServiceUUID(SERVICE_UUID);
  684.   pAdvertising->setScanResponse(true);
  685.   pAdvertising->setMinPreferred(0x06);
  686.   pAdvertising->setMinPreferred(0x12);
  687.   BLEDevice::startAdvertising();
  688. }
  689.  
  690. //-------------------------------------------------------------------------
  691. //////////              11. Bluetooth Management               ////////////
  692. //-------------------------------------------------------------------------
  693. //     C  hanges LED indication back to default color on disconnect      //
  694. //-------------------------------------------------------------------------
  695.  
  696. void RFduinoBLE_onDisconnect() {
  697.   BTisconnected = 0;
  698.   if (userColor > 0) {
  699.     r = userColor / 50; // r = 255 / 50 = 5
  700.     g = (userColor % 100) / 10; // g = 255 % 100 / 10 = 55 / 10 = 5
  701.     b = (userColor % 10); // b = 255 % 10 = 5
  702.   } else {
  703.     if (COLOR == RED) {
  704.       r = 5;
  705.       g = 0;
  706.       b = 0;
  707.     } else if (COLOR == GREEN) {
  708.       r = 0;
  709.       g = 5;
  710.       b = 0;
  711.     } else if (COLOR == BLK) {
  712.       r = 5;
  713.       g = 0;
  714.       b = 5;
  715.     } else {
  716.       r = 5;
  717.       g = 5;
  718.       b = 5;
  719.     }
  720.   }
  721. }
  722.  
  723. //-------------------------------------------------------------------------
  724. //     Throws up a splash screen on BT connect and turns LED Blue
  725. //     Freezes at power on ifconnected too early
  726. //-------------------------------------------------------------------------
  727.  
  728. void RFduinoBLE_onConnect() {
  729.   BTisconnected = 1;
  730.   r = 0;
  731.   g = 0;
  732.   b = 5;
  733.   BTRefresh = true;
  734. }
  735.  
  736. //-------------------------------------------------------------------------
  737. //             Changes variables when requested by phone                 //
  738. //-------------------------------------------------------------------------
  739.  
  740. void RFduinoBLE_onReceive(char *data, int len) {
  741.   int data_holder = 0;
  742.  
  743.   if (data[0]) { // Check the first byte of the incoming data XX
  744.     if (bitRead(data[0], 0)) { // 01 Change Increment: XX is hex number of displacement from 00 (0 mm) to FF (255000 micrometers = 255 mm = 10.039)  -- Increments of 10.039/255=.039 inches
  745.       minRepThreshold = (int)(data[1]) * 1000;
  746.     }
  747.     if (bitRead(data[0], 1)) { // 02 Change Usage Mode
  748.       data_holder = (int)(data[1]);
  749.       if (data_holder < 10) {
  750.         olyPowerMode();
  751.       }
  752.       // if (data_holder > 10) {
  753.       //   invertMode();
  754.       // }
  755.     }
  756.  
  757.     if (bitRead(data[0], 2)) { // 04 Change Test Frequency
  758.       testFrequency = (int)(data[1]);
  759.     }
  760.  
  761.     if (bitRead(data[0], 3)) { // 08 Change Tic Tolerance: XX from device where XX is the precision
  762.       if ((int)(data[1]) < 254) {
  763.         precisionCounter = max(1, (int)(data[1]));
  764.       } else if ((int)(data[1]) == 254) {
  765.         ticDiffprecision = 10;
  766.       } else if ((int)(data[1]) == 255) {
  767.         ticDiffprecision = 1;
  768.       }
  769.     }
  770.  
  771.     if (bitRead(data[0], 4)) { // 10 Change Display Timeout
  772.       backlightTime = data[1] * 1000;
  773.     }
  774.  
  775.     if (bitRead(data[0], 5)) { // 20 Navigate Displayed Rep Information
  776.       data_holder = (int)(data[1]);
  777.       if (data_holder < 10) {
  778.         if ((backlightFlag) && (repDisplay < (repDone + 2))) {
  779.           repDisplay += 1;
  780.         }
  781.       } else if (data_holder > 10 && data_holder < 20) {
  782.         if ((backlightFlag) && (repDisplay > 1) && (repDisplay < repDone + 2)) {
  783.           repDisplay -= 1;
  784.         }
  785.       }
  786.  
  787.       if (data_holder == 254) { // Output Raw Data to Display and Remove Filter
  788.         Filtration_Output = 0;
  789.         display.clearDisplay();
  790.         display.setTextSize(2);
  791.         display.setCursor(13, 0);
  792.         display.print("RAW VALUE");
  793.         display.setTextSize(2);
  794.         display.setCursor(28, 22);
  795.         display.print("OUTPUT");
  796.         display.setCursor(24, 42);
  797.         display.print("ENABLED");
  798.         display.display();
  799.       }
  800.  
  801.       if (data_holder == 255) { // Disable Data Compression
  802.         full_data_logging_enabled = 1;
  803.         precisionCounter = 1;
  804.         dataCOMPRESSION_enabled = 0;
  805.         ticDiffprecision = 1;
  806.         display.clearDisplay();
  807.         display.setTextSize(2);
  808.         display.setCursor(13, 0);
  809.         display.print("FULL DATA");
  810.         display.setTextSize(2);
  811.         display.setCursor(24, 22);
  812.         display.print("LOGGING");
  813.         display.setCursor(24, 42);
  814.         display.print("ENABLED");
  815.         display.display();
  816.       }
  817.     }
  818.  
  819.     if (bitRead(data[0], 6)) { // Send Configuration Status to Device
  820.       send_single_float(precisionCounter);
  821.       send_single_float(ticDiffprecision);
  822.       send_single_float(max_tick_time_allowable);
  823.       send_single_float(backlightTime);
  824.       send_single_float(minRepThreshold);
  825.       send_single_float(ticLength);
  826.       charge = 100; // fuelGauge.stateOfCharge();
  827.       send_single_float(charge);
  828.       send_single_float(unit_number);
  829.     }
  830.  
  831.     if (bitRead(data[0], 7)) { // Get New LED Color
  832.       data_holder = (int)(data[1]); // I.E. 255:
  833.       userColor = data_holder; // Store color
  834.       r = data_holder / 50; // r = 255/50 = 5
  835.       g = (data_holder % 100) / 10; // g = 255%100/10 = 55/10 = 5
  836.       b = (data_holder % 10); // b = 255%10 = 5
  837.     }
  838.  
  839.     if (bitRead(data[0], 8)) { // Send Current LED Color
  840.       data_holder = r * 50 + g * 10 + b;
  841.       send_single_float(data_holder);
  842.     }
  843.   }
  844. }
  845.  
  846. //-------------------------------------------------------------------------
  847. //                    Sends messages over Bluetooth                      //
  848. //-------------------------------------------------------------------------
  849.  
  850. void send_intList_charString(int *intList, int len) {
  851.   if (deviceConnected) {
  852.     String intString = "";
  853.     for (int i = 0; i < len; i++) {
  854.       if (i > 0) intString += ",";
  855.       intString += String(intList[i]);
  856.     }
  857.     pCharacteristic->setValue(intString.c_str());
  858.     pCharacteristic->notify();
  859.     delay(3);
  860.   }
  861. }
  862.  
  863. void send_intList(int *intList, int len) {
  864.   if (deviceConnected) {
  865.     for (int i = 0; i < len; i++) {
  866.       pCharacteristic->setValue((uint8_t*)&intList[i], sizeof(int));
  867.       pCharacteristic->notify();
  868.       delay(3);
  869.     }
  870.   }
  871. }
  872.  
  873. void send_floatList(float *floatList, int len) {
  874.   if (deviceConnected) {
  875.     for (int i = 0; i < len; i++) {
  876.       pCharacteristic->setValue((uint8_t*)&floatList[i], sizeof(float));
  877.       pCharacteristic->notify();
  878.       delay(3);
  879.     }
  880.   }
  881. }
  882.  
  883. //-------------------------------------------------------------------------
  884. //   Function to compress and send bulk velocity data over Bluetooth     //
  885. //-------------------------------------------------------------------------
  886.  
  887. // In order to save on transmission time the uint16s will be combined together (when possible).
  888. // The uint16_t are being combined like so:
  889. //        i.e: array foo where foo[0] = 16 and foo[1] = 23
  890. //        the numbers would be sent over as foo[0].(foo[1]/10000) or 16.0023.
  891. //        HOWEVER - The floats that are being sent can display up to 8 characters eg. 1234.5678 or 123456.78
  892. //It is therefore necessary to make sure that the values being sent over are not over 10,000 or
  893. //they will be truncated - Thus we check to make sure that the values aren't over 10,000 before combining
  894. //since we are combining every two values, ifthe list has an odd number of values we need to send the last one
  895.  
  896. void send_float_from_intList(uint16_t *intList, uint16_t len) {
  897.   if (deviceConnected) {
  898.     if (dataCOMPRESSION_enabled) {
  899.       for (int i = precisionCounter; i < ((len - moving_average_size) - precisionCounter); i = i + (2 * precisionCounter)) {
  900.         float value;
  901.         if ((intList[i] - 10000) < 0 && (intList[i + precisionCounter] - 10000) < 0) {
  902.           value = (float)intList[i] + (float)intList[i + precisionCounter] / 10000;
  903.         } else {
  904.           value = (float)intList[i];
  905.           pCharacteristic->setValue((uint8_t*)&value, sizeof(float));
  906.           pCharacteristic->notify();
  907.           delay(3);
  908.           value = (float)intList[i + precisionCounter];
  909.         }
  910.         pCharacteristic->setValue((uint8_t*)&value, sizeof(float));
  911.         pCharacteristic->notify();
  912.         delay(3);
  913.       }
  914.     } else {
  915.       for (int i = precisionCounter; i < ((len - moving_average_size) - precisionCounter); i = i + (precisionCounter)) {
  916.         float value = (float)intList[i];
  917.         pCharacteristic->setValue((uint8_t*)&value, sizeof(float));
  918.         pCharacteristic->notify();
  919.         delay(3);
  920.       }
  921.     }
  922.   }
  923. }
  924.  
  925. //-------------------------------------------------------------------------
  926. //                    Bluetooth Data Transmit Helpers                    //
  927. //-------------------------------------------------------------------------
  928.  
  929. void send_single_float(float singleFloat) {
  930.   if (deviceConnected) {
  931.     pCharacteristic->setValue((uint8_t*)&singleFloat, sizeof(float));
  932.     pCharacteristic->notify();
  933.     delay(3); // Bluetooth stack will go into congestion iftoo many packets are sent
  934.   }
  935. }
  936.  
  937. void send_all_data() {
  938.   if (sendData) {
  939.     repPerformance[0] = (float) rep; // Rep #
  940.     repPerformance[1] = (float) repArray[rep % repArrayCount]; // Avg Velocity (m/s)
  941.     repPerformance[2] = (float) dispArray[rep % repArrayCount]; // Range of Motion (mm)
  942.     repPerformance[3] = (float) peakVelocity[rep % repArrayCount]; // Peak Velocity (m/s)
  943.     repPerformance[4] = (float) peakVelLocation[rep % repArrayCount]; // Peak Velocity Location (%)
  944.     send_floatList(repPerformance, 5);
  945.     send_single_float(peakAccel); // Peak Acceleration (m/s^2)
  946.  
  947.     // Start OBV3 Extra Data
  948.     send_single_float(timeArray[rep % repArrayCount] * 1000000); // Duration of Rep (microseconds)
  949.     send_single_float(restTime); // Time between Reps (minutes)
  950.     send_single_float(tic_timestamp); // Timesatamp of Rep Completion (microseconds)
  951.     send_single_float(time_waiting); // Timestamp of time "waiting" in rep (microseconds)
  952.     send_single_float(max_tick_time_allowable); // Slowest Instantaneous Velocity Allowable (microseconds)
  953.     send_single_float(backlightTime); // Amount of Time the Backlight is allowed to stay on (microseconds)
  954.     send_single_float(minRepThreshold); // Minimum allowable Rep Length (micrometers)
  955.     send_single_float(dataCOMPRESSION_enabled); // Is data compression enabled for Bulk Data (bool)
  956.     send_single_float(Filtration_Output); // Is filtration enabled for bulk data (bool)
  957.  
  958.     // Device Info
  959.     send_single_float(CODE_VERSION); // Code Version
  960.     send_single_float(unit_number); // Unit Number
  961.     send_single_float(userColor); // LED Color (RGB)
  962.     send_single_float(BRIGHTNESS); // Brightness (%)
  963.     send_single_float(LOW_POWER); // Low Power Brightness (%)
  964.  
  965.     // Start Bulk Data Settings Transmission
  966.     send_single_float(-9999.0); // Flag Bulk Data Settings
  967.     send_single_float(precisionCounter); // # of Ticks Counted
  968.     send_single_float(ticDiffprecision); // Precision of Compressed Values
  969.     send_single_float(-9876.0); // Start Bulk Data
  970.     send_float_from_intList(myDTs, myDTCounter); // **BULK DATA** (UNKNOWN LENGTH)
  971.     send_single_float(-6789.0); // End Bulk Data
  972.     send_single_float((float)charge); // Battery Charge
  973.     sendData = false;
  974.   }
  975. }
  976.  
  977. //-------------------------------------------------------------------------
  978. //////////                   12. System Tray                   ////////////
  979. //-------------------------------------------------------------------------
  980. //     Adds rep number, battery and rest timer to the screen buffer      //
  981. //     Will be displayed to the screen outside of this function          //
  982. //-------------------------------------------------------------------------
  983.  
  984. void systemTrayDisplay() {
  985.   display.setTextColor(WHITE, BLACK);
  986.   display.setTextSize(1);
  987.   display.setCursor(0, 0);
  988.   display.print("Rep#:");
  989.  
  990.   if ((repDisplay < repDone) || (repDisplay == repDone)) { // this statement keeps the 'begin set' screen from showing repDisplay, which could be more than 1
  991.     display.print(repDisplay);
  992.   } else {
  993.     display.print("1");
  994.   }
  995.  
  996.   display.print("  ");
  997.   display.setCursor(55, 0);
  998.  
  999.   if ((repDisplay < repDone) || (repDisplay == repDone)) { // this statement allows the 'begin set' screen to show rest time
  1000.     display.print(rest[repDisplay % repArrayCount]);
  1001.   } else {
  1002.     display.print(restTime);
  1003.   }
  1004.   display.print(" min");
  1005.   display.setCursor(104, 0);
  1006.   display.print(charge);
  1007.   display.print("%");
  1008. }
  1009.  
  1010. //-------------------------------------------------------------------------
  1011. //////////             13. Rep Calculation Algorithm           ////////////
  1012. //-------------------------------------------------------------------------
  1013. //     Fields incoming tics, records data and updates values accordingly //
  1014. //-------------------------------------------------------------------------
  1015.  
  1016. void calcRep(bool isGoingUpward, int currentState) {
  1017.  
  1018. //-------------------------------------------------------------------------
  1019. //                            Initial Rep                                //
  1020. //-------------------------------------------------------------------------
  1021.  
  1022.   if (currentState != currentStateTemp) { // Check for change in direction (state changed in <Encoder State Interrupt, Section 15>)
  1023.     _initialized = 1; // See <Direction Flag, Section 4>
  1024.     tic_time = micros(); // Take start time for this rep
  1025.  
  1026.  
  1027. //-------------------------------------------------------------------------
  1028. //                    Going Up (Recording rep data)                      //
  1029. //-------------------------------------------------------------------------
  1030.  
  1031.     if (isGoingUpward) { // Check direction
  1032.       // displacement = counter_simplelengthbytic*ticLength; // increment or decrement the distance by one tic length, depending on direction -->
  1033.       micros_holder = micros();
  1034.  
  1035.       if ((micros_holder - tic_timestamp) > max_tick_time_allowable) {
  1036.         time_waiting = time_waiting + micros_holder - tic_timestamp;
  1037.       }
  1038.       // There was a bug found where it was possible to start going up but then hold a
  1039.       // position without going down...this caused the total_time to
  1040.       // continually increase and throw off the average velocity for the rep - to compensate
  1041.       // for this we see how much time someone is waiting and
  1042.       // subtract that from the total_time
  1043.  
  1044.       tic_timestampLast2 = tic_timestampLast;
  1045.       tic_timestampLast = tic_timestamp;
  1046.       tic_timestamp = micros_holder;
  1047.  
  1048.  
  1049. //-------------------------------------------------------------------------
  1050. //                          Starting New Rep                             //
  1051. //-------------------------------------------------------------------------
  1052.  
  1053.     if (!isGoingUpwardLast) { // If you were just going downward clear your array so you can start a fresh rep
  1054.       memset(myDTs, 0, sizeof(myDTs)); // Zero out tic array
  1055.       moving_average_holder = 0; // Reset current average velocity
  1056.       //memset(FILTER_out,0,sizeof(FILTER_out));
  1057.       memset(moving_average_vector, 0, sizeof(moving_average_vector)); // Reset velocity array
  1058.       //memset(instVelTimestamps,0,sizeof(instVelTimestamps));
  1059.       time_waiting = 0; // Reset wait time
  1060.       counter_simplelengthbytic = 0; // Reset interrupt tic counter
  1061.       starttime = tic_timestamp; // New rep started
  1062.       send_floatList(startMessage, 1); // Tell app new rep is starting via BT
  1063.       rep += 1; // Increase rep count
  1064.       currentInstVel = 0;
  1065.       lastInstVel = 0;
  1066.       peak_vel_at = 0;
  1067.       minDT = 1000000;
  1068.       myDTCounter = 0; // Zero out position data
  1069.       peakAccel = 0;
  1070.     }
  1071.  
  1072.     // keeping instantaneous velocities for our peak velocity reading
  1073.     // instVelTimestamps[counter_lengthbyticinfunction] = (unsigned int)(tic_timestamp-tic_timestamp_last);
  1074.  
  1075.     ticDiff = tic_timestamp - tic_timestamp_last; // DT for this rep
  1076.     tic_timestamp_last = tic_timestamp; // Base time for next rep
  1077.  
  1078. //-------------------------------------------------------------------------
  1079. //                            Moving Average                             //
  1080. //-------------------------------------------------------------------------
  1081.  
  1082.       for (int shift_i = 0; shift_i < (moving_average_size - 1); shift_i++) { // Going up, shift the values back (losing the first value) so that we can put our new value on the end
  1083.         moving_average_vector[shift_i] = moving_average_vector[shift_i + 1]; // Improve values by loading (til end) with last recorded value
  1084.       }
  1085.  
  1086.       moving_average_vector[moving_average_size - 1] = ticDiff * one_over_moving_average_size; // push new tic (time between encoder high) onto end of array
  1087.  
  1088.       if (myDTCounter >= (moving_average_size)) { // If moving average array is full (more than 16 tics) -->
  1089.         moving_average_holder = 0; //  Zero out moving average
  1090.  
  1091.         for (int i = 0; i <= (moving_average_size - 1); i++) {
  1092.           moving_average_holder = moving_average_holder + moving_average_vector[i]; // Add up vector to get the average velocity
  1093.         }
  1094.  
  1095.         if (last_avg > moving_average_holder) {
  1096.           // Calculate peak acceleration --> dV/dT
  1097.           peakAccelHolder = (((float)ticLength / (float)moving_average_holder) - ((float)ticLength / (float)last_avg)) / ((float)moving_average_holder / 1000000);
  1098.         } else {
  1099.           // peakAccelHolder = 0;
  1100.         }
  1101.  
  1102.         last_avg = moving_average_holder;
  1103.  
  1104.         if (peakAccelHolder > peakAccel) {
  1105.           peakAccel = peakAccelHolder;
  1106.         }
  1107.  
  1108.         ticDiffFiltered = moving_average_holder;
  1109.         // end moving average
  1110.  
  1111.         if (ticDiffFiltered < minDT) { // if the last tic was faster than the current lowest (minDT)
  1112.           minDT = ticDiffFiltered; // new minimum velocity is the current
  1113.           peak_vel_at = myDTCounter; // save reference to this tic (required)
  1114.         }
  1115.       } else {
  1116.         // moving_average_holder = moving_average_holder + ticDiff;
  1117.         //
  1118.         // if (myDTCounter > 1) {
  1119.         //   moving_average_holder=(moving_average_holder / 2);
  1120.         // }
  1121.         //
  1122.         // ticDiffFiltered = moving_average_holder;
  1123.         ticDiffFiltered = 0;
  1124.       }
  1125.  
  1126.       if (myDTCounter >= moving_average_size - 1) {
  1127.         // precisionCounter = myDTCounter / (highPrecisionMode + 1);
  1128.         if (myDTCounter < myDTCounter_size) {
  1129.             myDTs[myDTCounter - moving_average_size] = (uint16_t)(ticDiffFiltered / ticDiffprecision); // start filling tic array with average velocities
  1130.           if (Filtration_Output == 0) {
  1131.             myDTs[myDTCounter] = (uint16_t)(ticDiff / ticDiffprecision); // start filling tic array with unfiltered velocities
  1132.           }
  1133.         }
  1134.       }
  1135.       myDTCounter++; // End of GoingUp, increase encoder tic total by 1
  1136.     } else {
  1137.       // If you're going downward, and you were just going upward, you potentially just finished a rep.
  1138.       // Do your math, check if it fits the rep criteria, and store it in an array.
  1139.  
  1140. //-------------------------------------------------------------------------
  1141. //                            Rep Calculations                           //
  1142. //-------------------------------------------------------------------------
  1143.  
  1144.       if (isGoingUpwardLast) { // Modified for overflow reps
  1145.         displacement = counter_simplelengthbytic * ticLength; // Total distance moved
  1146.  
  1147.         if (displacement > minRepThreshold) { // If distance traveled is enough to qualify as one rep
  1148.           total_time = (tic_timestamp - starttime) - time_waiting; // Calculate time since start
  1149.           peakVelocity[rep % repArrayCount] = float(ticLength) / float(minDT);
  1150.           dispArray[rep % repArrayCount] = displacement / 1000; // Update displacement array
  1151.           timeArray[rep % repArrayCount] = (float)total_time / 1000000; // Update time array (time per rep)
  1152.           peakVelLocation[rep % repArrayCount] = (peak_vel_at * 100) / myDTCounter; // Update log of peak velocity locations
  1153.           repArray[rep % repArrayCount] = ((float)(counter_simplelengthbytic * ticLength) / (float)(total_time / 1000)) / 1000; // Get total rep time and store in array
  1154.           rest[rep % repArrayCount] = 0; // Reset rest time just in case it's reused
  1155.  
  1156.           if (rep > 1) {
  1157.             rest[rep % repArrayCount - 1] = restTime; // Set the rest time of the previous rep
  1158.           }
  1159.  
  1160.           repDone = rep; // Sets global rep counter to loop rep count
  1161.           minTimer = millis(); // resets 60 second rest time counter
  1162.           minTimer2 = millis();
  1163.           restTime = 0;
  1164.           counter_simplelengthbytic = 0;
  1165.         } else { // Get rid of this rep (it doesn't count)
  1166.           rep -= 1;
  1167.         }
  1168.       }
  1169.  
  1170.       displacement -= ticLength; // Subtract this amount from total distance traveled (it doesn't qualify as rep distance)
  1171.     }
  1172.  
  1173.     isGoingUpwardLast = isGoingUpward; // Sets globally that the last state was going upward
  1174.     currentStateTemp = currentState; // Is this necessary?          *****
  1175.   }
  1176. }
  1177.  
  1178. //-------------------------------------------------------------------------
  1179. //////////          14. Button Press State Configuration       ////////////
  1180. //-------------------------------------------------------------------------
  1181. //     Handles Button presses and incorporates most helper functions     //
  1182. //-------------------------------------------------------------------------
  1183.  
  1184.  
  1185. void buttonStateCalc() {
  1186.   // Read button state once per loop
  1187.   buttonstateL = !digitalRead(pin_buttonLeft);
  1188.   buttonstateR = !digitalRead(pin_buttonRight);
  1189.  
  1190.   // Update rep to be displayed to the screen if you recorded a new rep
  1191.   if (repDone != repDoneLast) {
  1192.     repDisplay = repDone;
  1193.  
  1194.     // RepDisplayLast and repDoneLast are reset below
  1195.     if (!backlightFlag) { // Turn on display ifit's off
  1196.       display.ssd1306_command(SSD1306_DISPLAYON);
  1197.       systemTrayDisplay();
  1198.       display.display();
  1199.     }
  1200.  
  1201.     sendData = true;
  1202.   }
  1203.  
  1204. //-------------------------------------------------------------------------
  1205. //                            Right Button Press                         //
  1206. //-------------------------------------------------------------------------
  1207.  
  1208.   if (buttonstateRtemp && !buttonstateR) { // Register a button press on the release of the right button
  1209.     if ((backlightFlag) && (repDisplay < (repDone + 2))) { // If the screen is on and the current displayed rep is not the last
  1210.       repDisplay += 1;
  1211.     } else {
  1212.       display.ssd1306_command(SSD1306_DISPLAYON);
  1213.       backlightFlag = 1;
  1214.       // systemTrayDisplay();
  1215.       display.display();
  1216.     }
  1217.  
  1218.     rightHold = 0;
  1219.     RbuttonDepressed = 0;
  1220.     // This flag forces the double hold to execute its code for only one loop
  1221.     accomplishedDoubleHold = false;
  1222.     accomplishedSingleHold = false;
  1223.     displayTime = millis(); // Starts display time-out timer
  1224.     // bluetoothStartNextLoop = true;
  1225.   }
  1226. //-------------------------------------------------------------------------
  1227. //                            Left Button Press                          //
  1228. //-------------------------------------------------------------------------
  1229.  
  1230.   if (buttonstateLtemp && !buttonstateL) { // Register a button press on the release of the left button
  1231.     if ((backlightFlag) && (repDisplay > 1) && (repDisplay < repDone + 2)) { // If the screen is on and the current displayed rep is not the first or last
  1232.       if (repDone <= 100 || (repDisplay - 1 > repDone % repArrayCount)) {
  1233.         repDisplay -= 1;
  1234.       }
  1235.     } else {
  1236.       display.ssd1306_command(SSD1306_DISPLAYON);
  1237.       backlightFlag = 1;
  1238.       // systemTrayDisplay();
  1239.       display.display();
  1240.     }
  1241.  
  1242.     leftHold = 0;
  1243.     LbuttonDepressed = 0;
  1244.     accomplishedDoubleHold = false; // This flag forces the double hold to execute its code for only one loop
  1245.     accomplishedSingleHold = false;
  1246.     displayTime = millis(); // Starts display time-out timer
  1247.   }
  1248.  
  1249. //-------------------------------------------------------------------------
  1250. //                              Press and Hold                           //
  1251. //-------------------------------------------------------------------------
  1252.  
  1253.   if (!buttonstateRtemp && buttonstateR) { // Set a flag if you just pressed the right button and start hold timer
  1254.     rightHold = millis();
  1255.     RbuttonDepressed = 1;
  1256.   }
  1257.  
  1258.   if (!buttonstateLtemp && buttonstateL) { // Set a flag if you just pressed the left button and start hold timer
  1259.     leftHold = millis();
  1260.     LbuttonDepressed = 1;
  1261.   }
  1262.  
  1263.   if (LbuttonDepressed && RbuttonDepressed) { // if both buttons are depressed start invert mode
  1264.     // doubleclick = !doubleclick; // function to enable peak acceleration in olympic mode
  1265.     // if (((millis() - rightHold) > bothHoldActionTime) && ((millis() - leftHold) > bothHoldActionTime)) {
  1266.     //   if (!accomplishedDoubleHold) {
  1267.     //     invertMode();
  1268.     //   }
  1269.     // }
  1270.   } else if (LbuttonDepressed || RbuttonDepressed) { // fixes a bug where in certain situations the left button will keep the switching screens from clearing
  1271.     if (((millis() - rightHold) > singleHoldActionTime) && ((millis() - leftHold) > singleHoldActionTime)) {
  1272.       if (!accomplishedSingleHold) {
  1273.         accomplishedSingleHold = true;
  1274.  
  1275.         olyPowerMode(); // Start olympic mode
  1276.         if (LbuttonDepressed) {
  1277.           repDisplay++; // Redundant code to increment reps if missed above?          *****
  1278.         }
  1279.         if (RbuttonDepressed) {
  1280.           repDisplay--;
  1281.         }
  1282.       }
  1283.     }
  1284.   }
  1285.  
  1286. //-------------------------------------------------------------------------
  1287. //                              Display Change                           //
  1288. //-------------------------------------------------------------------------
  1289.  
  1290.   if ((repDisplay != repDisplayLast) || (repDone != repDoneLast)) { // if the displayed rep changes, keep the time so we know when to dim the backlight
  1291.     displayTime = millis();
  1292.     // make sure we can see the new rep
  1293.     display.ssd1306_command(SSD1306_DISPLAYON);
  1294.     backlightFlag = 1;
  1295.  
  1296. //-------------------------------------------------------------------------
  1297. //                              Past Set Move                            //
  1298. //-------------------------------------------------------------------------
  1299.  
  1300.     if (repDisplay == (repDone + 1)) { // This 'if' statement keeps you from going from "Begin Set" back to "Delete Past Set?"
  1301.       if ((repDisplayLast < (repDone + 1)) || BTRefresh) {
  1302.         BTRefresh = false;
  1303.         display.clearDisplay();
  1304.         systemTrayDisplay();
  1305.         display.setTextSize(1);
  1306.         display.setCursor(0, 0);
  1307.         display.print("Rep#:");
  1308.         display.print(repDisplay - 1);
  1309.         display.print("  ");
  1310.         display.setTextSize(2);
  1311.         display.setTextColor(WHITE);
  1312.         display.setCursor(0, 9);
  1313.         display.println("Delete");
  1314.         display.println("Past Set?");
  1315.         display.setTextSize(1);
  1316.         display.setCursor(0, 40);
  1317.         display.println("R Button - Delete Set");
  1318.         display.println("L Button - Go Back");
  1319.         display.display();
  1320.       }
  1321.     } else if (repDisplay > (repDone + 1)) { // This line keeps the repDisplay value from getting too big, and causing a bug to miss the first rep (edit: might not be necessary)  *****
  1322.       counter_simplelengthbytic = 0; // JDLTEST
  1323.       // repDisplay = repDone + 2;
  1324.       rep = (goingUpward) ? (1) : (0);
  1325.       repDone = 0;
  1326.       repDoneLast = 0;
  1327.  
  1328.       display.clearDisplay();
  1329.       display.setTextSize(2);
  1330.       display.setTextColor(WHITE, BLACK);
  1331.       display.setCursor(0, 15);
  1332.       display.print("Begin Set!");
  1333.       systemTrayDisplay();
  1334.       display.setTextSize(1);
  1335.       display.setCursor(0, 0);
  1336.       display.print("Rep#:1  ");
  1337.       display.display();
  1338.       delay(1);
  1339.  
  1340.       memset(repArray, 0, sizeof(repArray));
  1341.       memset(myDTs, 0, sizeof(myDTs));
  1342.       memset(dispArray, 0, sizeof(dispArray));
  1343.       memset(timeArray, 0, sizeof(timeArray));
  1344.       memset(peakVelocity, 0, sizeof(peakVelocity));
  1345.       // FOR TESTING
  1346.       // memset(FILTER_out,0,sizeof(FILTER_out));
  1347.       memset(moving_average_vector, 0, sizeof(moving_average_vector));
  1348.       moving_average_holder = 0;
  1349.       // memset(instVelTimestamps,0,sizeof(instVelTimestamps));
  1350.       myDTCounter = 0;
  1351.     } else { // If in standard operating mode ->
  1352. //-------------------------------------------------------------------------
  1353. //                    Rep Information Display Logic                      //
  1354. //-------------------------------------------------------------------------
  1355.       if (!flipPowerOlyScreen) {
  1356.         display.clearDisplay();
  1357.         display.setTextSize(1);
  1358.         display.setTextColor(WHITE, BLACK);
  1359.         display.setCursor(0, 9);
  1360.         display.print("Avg Vel:");
  1361.         display.setTextSize(3);
  1362.         display.setTextColor(WHITE, BLACK);
  1363.         display.setCursor(0, 19);
  1364.         display.print(repArray[repDisplay % repArrayCount]);
  1365.         display.setTextSize(1);
  1366.         display.print("m/s");
  1367.         display.setCursor(0, 42);
  1368.         display.print("Peak Vel:");
  1369.         display.setCursor(0, 51);
  1370.  
  1371.         if (peakVelocity[repDisplay % repArrayCount] > MAXVEL) {
  1372.           display.print("MAX");
  1373.         } else {
  1374.           display.print(peakVelocity[repDisplay % repArrayCount]);
  1375.           display.print("m/s");
  1376.         }
  1377.  
  1378.         // display.print(myDTs[10]);
  1379.         // display.print(myDTCounter/2);
  1380.         display.setCursor(82, 42);
  1381.         display.print("ROM:");
  1382.         display.setCursor(82, 51);
  1383.         display.print(dispArray[repDisplay % repArrayCount]);
  1384.         display.print("mm");
  1385.  
  1386.         if (testbed_readouts) {
  1387.           display.setTextSize(1);
  1388.           display.setCursor(100, 12);
  1389.           display.print(peak_vel_at);
  1390.  
  1391.           display.setCursor(100, 22);
  1392.           display.print(myDTCounter);
  1393.         }
  1394.        } else {
  1395.         display.clearDisplay();
  1396.         display.setTextSize(1);
  1397.         display.setTextColor(WHITE, BLACK);
  1398.         display.setCursor(0, 9);
  1399.  
  1400.         if (doubleclick) {
  1401.           display.print("Peak Accel:");
  1402.         } else {
  1403.           display.print("Peak Vel:");
  1404.         }
  1405.  
  1406.         display.setTextSize(3);
  1407.         display.setTextColor(WHITE, BLACK);
  1408.         display.setCursor(0, 19);
  1409.  
  1410.         if (doubleclick) {
  1411.           display.print(peakAccel);
  1412.           display.setTextSize(1);
  1413.           display.print("m/s^2");
  1414.         } else {
  1415.           if (peakVelocity[repDisplay % repArrayCount] > MAXVEL) {
  1416.             display.print("MAX");
  1417.           } else {
  1418.             display.print(peakVelocity[repDisplay % repArrayCount]);
  1419.             display.setTextSize(1);
  1420.             display.print("m/s");
  1421.           }
  1422.         }
  1423.  
  1424.         display.setTextSize(1);
  1425.         display.setCursor(0, 42);
  1426.         display.print("Time:");
  1427.         display.setCursor(0, 51);
  1428.         display.print(timeArray[repDisplay % repArrayCount]);
  1429.         display.print("sec");
  1430.         display.setTextSize(1);
  1431.         display.setCursor(82, 42);
  1432.         display.print("PeakHt:");
  1433.         display.setCursor(82, 51);
  1434.         display.print(peakVelLocation[repDisplay % repArrayCount]);
  1435.         display.print("%");
  1436.       }
  1437.  
  1438.       systemTrayDisplay();
  1439.       display.display();
  1440.  
  1441.       if (BTisconnected) {
  1442.         send_all_data(); // moved send_all_data here so it doesn't lag the display
  1443.       }
  1444.     }
  1445.     repDoneLast = repDone;
  1446.     repDisplayLast = repDisplay;
  1447.   }
  1448.  
  1449.   buttonstateRtemp = buttonstateR;
  1450.   buttonstateLtemp = buttonstateL;
  1451. }
  1452.  
  1453. //-------------------------------------------------------------------------
  1454. //////////             15. Encoder State Interrupt             ////////////
  1455. //-------------------------------------------------------------------------
  1456. //        Increments pulled length when encoder activity is detected     //
  1457. //-------------------------------------------------------------------------
  1458.  
  1459. // void encoderState() {
  1460. //   state = !state;
  1461. //
  1462. //   if (goingUpward) { // This if statement keeps the counter from counting on downward movements
  1463. //     counter_simplelengthbytic++; // This is the counter that counts the number of encoder wheel transitions in the interrupt
  1464. //   }
  1465. // }
  1466.  
  1467. // void IRAM_ATTR encoderState() {
  1468. //   state = !state;
  1469. //
  1470. //   if (goingUpward) { // This if statement keeps the counter from counting on downward movements
  1471. //     counter_simplelengthbytic++; // This is the counter that counts the number of encoder wheel transitions in the interrupt
  1472. //   }
  1473. // }
  1474.  
  1475. static unsigned long lastDebounceTime = 0;
  1476.  
  1477. void IRAM_ATTR encoderState() {
  1478.   unsigned long now = micros();
  1479.   if (now - lastDebounceTime > 500) {
  1480.     lastDebounceTime = now;
  1481.     state = !state;
  1482.  
  1483.     if (goingUpward) {
  1484.       counter_simplelengthbytic++;
  1485.     }
  1486.   }
  1487. }
  1488.  
  1489. // volatile unsigned long lastInterruptTime = 0;
  1490. // const unsigned long debounceDelay = 1000; // in microseconds (1ms)
  1491. //
  1492. // void IRAM_ATTR encoderState() {
  1493. //   unsigned long now = micros();
  1494. //   if (now - lastInterruptTime > debounceDelay) {
  1495. //     lastInterruptTime = now;
  1496. //
  1497. //     if (goingUpward) {
  1498. //       counter_simplelengthbytic++;
  1499. //     }
  1500. //   }
  1501. // }
  1502.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement