dmjlambert

Arduino cruise control button gesture processor

Dec 13th, 2021 (edited)
1,517
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 27.36 KB | None | 0 0
  1. /*
  2.   The GM 67-80 turn signal lever with single button cruise control
  3.   has 2 switches inside it that switch at different depths of the
  4.   button push.  Because of this, it facilitates the ability to
  5.   detect a fast or slow button release or press.
  6.  
  7.   This Arduino sketch is intended to interpret the fast or slow
  8.   presses and releases, long duration press, double tap, and
  9.   other gestures, and do separate actions in response.
  10.   In this way the Arduino can do a variety of things based on
  11.   input from one button, such as roll up and down power windows,
  12.   or turn things on or off.
  13.  
  14.   The patterns tapped on the button remind me of morse code, so
  15.   in this sketch I name many of the patterns using dits and dahs.
  16.  
  17.   Connection of the Arduino to serial monitor allows you to
  18.   capture the patterns input with the button as array values,
  19.   so you can easily alter the sketch for unique patterns.
  20.  
  21.   Electrical connections on the GM 67-80 turn signal lever:
  22.   Pin 1 and pin 2 are separated by a notch
  23.   Pin 1 normally open and switches closed at shallow depression
  24.   Pin 2 common
  25.   Pin 3 normally closed and switches open at deep depression
  26.  
  27.      Recognition of pass through of cruise control coast and set
  28.   signals requires slow press and hold input to this sketch.
  29.   What is passed to cruise control is fast press and hold,
  30.   followed by the actual speed of button release.  Any speed
  31.   press followed by slow release is typically required for cruise
  32.   control to set properly.
  33.   In my experience with GM 67-80 single button cruise control in
  34.   various vehicles, fast release may sometimes disengage cruise,
  35.   but it is not reliable as a method of disengagement.  In some
  36.   models a fast press and release may accelerate and set a new
  37.   faster speed by a couple miles per hour.   Passing through
  38.   settings that allow the cruise control to do these advanced
  39.   features is not directly supported by this sketch, and all that
  40.   I intend it to do is coast and set.  However, it is possible
  41.   to use non-pass-through gestures (all the gestures other than
  42.   slow press and hold) to do things such as accelerate and
  43.   disengage if you figure out how to wire those features into
  44.   the cruise control.
  45.   The sky is the limit regarding complexity of the button press
  46.   gestures and resulting signals to external relays.
  47.  
  48.      Examples of things to control with this:
  49.   roll power windows
  50.   wiper mist
  51.   hidden garage door remote
  52.   push button start
  53.   kill switch
  54.   external or internal lights
  55.   switch on or off assorted accessories
  56.   cruise control
  57.  
  58.   Notes about matching arrays:
  59.   clean collected array:  this means remove the leading delay time,
  60.   which means nothing, and if in the middle of the pattern there is
  61.   a checkForMatchesTimer delay time and event, remove the
  62.   checkForMatchesTimer expiration event
  63.   and combine (add) the expiration time with the next delay time
  64.   that happens before the next button activity event.
  65.   map array: this means change the event timings to all be measured
  66.   from 0 to 100, instead of 0 to 1500 or some other arbitrary number.
  67.   The final array to match a pattern ends up showing you timings that
  68.   are percentages of the longest event.   The longest event used
  69.   for pattern matching is typically less than a checkForMatchesTimer
  70.   expiration, and is perhaps 1/2 second shown by approximately 80 in the
  71.   array.
  72.   match against some patterns special cases:
  73.   for patterns that have 999 in a specific time slot, that indicates ignore
  74.   that time slot in the collected array, do that by insert 999 in same slot
  75.   of cleaned array, re-map, and compare.
  76.   The purpose of ignoring certain times is to make it possible ot match
  77.   patterns where the button is held down while waiting for a controlled
  78.   device to do something such as coast on cruise control or roll up or roll
  79.   down window until the button is released.  I don't know that the
  80.   finished application will actually use this feature of ignoring certain
  81.   timing durations, but the feature is there should it be desired.
  82.   In order to create a pattern for an arbitrary long press it is necessary
  83.   to put 999 in a pattern, compile, upload, and capture the mapped pattern,
  84.   then copy that mapped pattern into the pattern array settings to use as
  85.   the model.
  86.   This is version 15
  87.   Demo of earlier version (13):  https://youtu.be/xDpqLDz1xEk
  88.  
  89.   MIT license
  90.   Copyright (c) 2021 David Lambert
  91.  
  92.   Permission is hereby granted, free of charge, to any person obtaining a copy
  93.   of this software and associated documentation files (the "Software"), to deal
  94.   in the Software without restriction, including without limitation the rights
  95.   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  96.   copies of the Software, and to permit persons to whom the Software is
  97.   furnished to do so, subject to the following conditions:
  98.  
  99.   The above copyright notice and this permission notice shall be included in all
  100.   copies or substantial portions of the Software.
  101.  
  102.   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  103.   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  104.   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  105.   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  106.   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  107.   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  108.   SOFTWARE.
  109. */
  110.  
  111. // Global settings
  112.  
  113. // pin names
  114. #define SWITCHSHALLOW 3  // digital input from button shallow press
  115. #define SWITCHDEEP    4  // digital input from button deep press
  116. #define OUTPUT1       5
  117. #define OUTPUT2       6
  118. #define OUTPUT3       7
  119. #define OUTPUT4       8
  120. #define OUTPUT5       9
  121. #define OUTPUT6      10
  122. #define OUTPUT7      11
  123. #define OUTPUT8      12
  124. #define OUTPUT9      13
  125. #define OUTPUT10     A0
  126. #define OUTPUT11     A1
  127. #define OUTPUT12     A2
  128. #define OUTPUT13     A3
  129.  
  130. // debounce settings
  131. unsigned long lastDebounceTime1 = 0;  // the last time the output pin was toggled
  132. unsigned long lastDebounceTime2 = 0;  // the last time the output pin was toggled
  133. const unsigned long debounceDelay = 10;    // the debounce time; increase if the output flickers
  134. bool buttonState1 = LOW;             // the current reading from the input pin
  135. bool lastButtonState1 = LOW;         // the previous reading from the input pin
  136. bool buttonState2 = LOW;             // the current reading from the input pin
  137. bool lastButtonState2 = LOW;         // the previous reading from the input pin
  138. bool buttonChange1 = false;
  139. bool buttonChange2 = false;
  140.  
  141. // timer settings
  142. unsigned long output9Timer = 0;
  143. unsigned long output9TimerDuration;
  144. bool output9TimerCounted = true;
  145. unsigned long output10Timer = 0;
  146. unsigned long output10TimerDuration;
  147. bool output10TimerCounted = true;
  148. unsigned long checkForMatchesTimer = 0;
  149. unsigned long resetArrayTimer = 0;
  150. bool checkForMatchesTimerCounted = true;
  151. bool resetArrayTimerCounted = true;
  152. const unsigned long checkForMatchesTimerDuration = 900;
  153. const unsigned long resetArrayTimerDuration = 925;
  154.  
  155. // names of events and numbers assigned to them
  156. #define SwitchShallowPressed           1
  157. #define SwitchDeepPressed              2
  158. #define SwitchDeepReleased             3
  159. #define SwitchShallowReleased          4
  160. #define checkForMatchesTimerExpired   13
  161. #define resetArrayTimerExpired        14
  162.  
  163. // array variables
  164. unsigned int index = 0;
  165. #define ARRAYLENGTH  30
  166. #define ERRORPERCENT 20
  167. unsigned int collectedPattern[ARRAYLENGTH];
  168. unsigned int collectedPatternCleaned[ARRAYLENGTH];
  169. unsigned int collectedPatternMapped[ARRAYLENGTH];
  170.  
  171. // The patterns to be recognized when compared against button
  172. // presses and releases of different timings.   There are
  173. // more than one pattern for most of these gestures, to make
  174. // the sketch more reliably pick up on slightly different ways
  175. // to do the gesture.
  176. // slow press and hold.  This is pass through of cruise control coast and set command
  177. const PROGMEM unsigned int slowPressAndHold[ARRAYLENGTH] = {1, 29, 2, 100, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  178. const PROGMEM unsigned int slowPressAndHold2[ARRAYLENGTH] = {1, 62, 2, 100, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  179. // fastPressAndHold (fast press with long hold.  Release immediately turns off device)
  180. const PROGMEM unsigned int fastPressAndHold[ARRAYLENGTH] = {1, 1, 2, 100, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  181. // dit-dah-and-hold (fast press and release followed by press and hold.  Release immediately turns off device)
  182. const PROGMEM unsigned int ditDahAndHold[ARRAYLENGTH] = {1, 4, 2, 15, 3, 2, 4, 21, 1, 1, 2, 100, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  183. const PROGMEM unsigned int ditDahAndHold2[ARRAYLENGTH] = {1, 2, 2, 38, 3, 2, 4, 36, 1, 2, 2, 100, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  184. // dit-dit-dah-and-hold (fast double tap followed by press and hold.  Release immediately turns off device)
  185. const PROGMEM unsigned int ditDitDahAndHold[ARRAYLENGTH] = {1, 3, 2, 20, 3, 1, 4, 17, 1, 1, 2, 17, 3, 1, 4, 26, 1, 2, 2, 100, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  186. const PROGMEM unsigned int ditDitDahAndHold2[ARRAYLENGTH] = {1, 2, 2, 41, 3, 1, 4, 39, 1, 2, 2, 38, 3, 1, 4, 46, 1, 2, 2, 100, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  187. // dit (fast single tap)
  188. const PROGMEM unsigned int dit[ARRAYLENGTH] = {1, 2, 2, 25, 3, 1, 4, 100, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  189. const PROGMEM unsigned int dit2[ARRAYLENGTH] = {1, 3, 2, 49, 3, 1, 4, 100, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  190. // dit-dit (fast double tap)
  191. const PROGMEM unsigned int ditDit[ARRAYLENGTH] = {1, 2, 2, 25, 3, 1, 4, 14, 1, 4, 2, 20, 3, 2, 4, 100, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  192. const PROGMEM unsigned int ditDit2[ARRAYLENGTH] = {1, 2, 2, 26, 3, 1, 4, 40, 1, 3, 2, 21, 3, 1, 4, 100, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  193. // dit-dit-dit (fast tripple tap)
  194. const PROGMEM unsigned int ditDitDit[ARRAYLENGTH] = {1, 2, 2, 25, 3, 1, 4, 14, 1, 4, 2, 20, 3, 2, 4, 14, 1, 4, 2, 20, 3, 2, 4, 100, 13, 0, 0, 0, 0, 0};
  195. const PROGMEM unsigned int ditDitDit2[ARRAYLENGTH] = {1, 1, 2, 24, 3, 1, 4, 35, 1, 1, 2, 24, 3, 1, 4, 38, 1, 1, 2, 22, 3, 1, 4, 100, 13, 0, 0, 0, 0, 0};
  196. // comment about dah (long press) this one may be too similar to press and hold.
  197. // Having a dit following dah seems to limit my tendency to make
  198. // a long press too long, so dah-dit and dah-dit-dit are better gestures.
  199. // dah-dit
  200. const PROGMEM unsigned int dahDit[ARRAYLENGTH] = {1, 2, 2, 85, 3, 2, 4, 15, 1, 3, 2, 17, 3, 1, 4, 100, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  201. const PROGMEM unsigned int dahDit2[ARRAYLENGTH] = {1, 1, 2, 59, 3, 1, 4, 24, 1, 1, 2, 24, 3, 1, 4, 100, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  202. // dah-dit-dit
  203. const PROGMEM unsigned int dahDitDit[ARRAYLENGTH] = {1, 3, 2, 69, 3, 1, 4, 23, 1, 1, 2, 24, 3, 1, 4, 16, 1, 1, 2, 28, 3, 1, 4, 100, 13, 0, 0, 0, 0, 0};
  204. const PROGMEM unsigned int dahDitDit2[ARRAYLENGTH] = {1, 2, 2, 90, 3, 1, 4, 21, 1, 1, 2, 27, 3, 1, 4, 25, 1, 1, 2, 32, 3, 1, 4, 100, 13, 0, 0, 0, 0, 0};
  205. // comment about dit-dah, in testing I found this one is too
  206. // similar to dit-dah-and-hold and cause unintended results
  207. // dit-dah-dit
  208. const PROGMEM unsigned int ditDahDit[ARRAYLENGTH] = {1, 2, 2, 23, 3, 1, 4, 20, 1, 1, 2, 72, 3, 1, 4, 20, 1, 1, 2, 20, 3, 1, 4, 100, 13, 0, 0, 0, 0, 0};
  209. const PROGMEM unsigned int ditDahDit2[ARRAYLENGTH] = {1, 3, 2, 27, 3, 1, 4, 23, 1, 1, 2, 81, 3, 1, 4, 33, 1, 1, 2, 43, 3, 1, 4, 100, 13, 0, 0, 0, 0, 0};
  210. const PROGMEM unsigned int ditDahDit3[ARRAYLENGTH] = {1, 3, 2, 28, 3, 1, 4, 25, 1, 2, 2, 84, 3, 1, 4, 31, 1, 2, 2, 42, 3, 1, 4, 100, 13, 0, 0, 0, 0, 0};
  211.  
  212. // Array of names of all the patterns we want to detect:
  213. #define NUMPATTERNS 20
  214. unsigned int patternIndex = 0;
  215. const PROGMEM unsigned int patternTable[NUMPATTERNS] = {
  216.   slowPressAndHold,
  217.   slowPressAndHold2,
  218.   fastPressAndHold,
  219.   ditDahAndHold,
  220.   ditDahAndHold2,
  221.   ditDitDahAndHold,
  222.   ditDitDahAndHold2,
  223.   dit,
  224.   dit2,
  225.   ditDit,
  226.   ditDit2,
  227.   ditDitDit,
  228.   ditDitDit2,
  229.   dahDit,
  230.   dahDit2,
  231.   dahDitDit,
  232.   dahDitDit2,
  233.   ditDahDit,
  234.   ditDahDit2,
  235.   ditDahDit3
  236. };
  237.  
  238. // decision handling variables
  239. bool onHold5 = false;
  240. bool onHold6 = false;
  241. bool onHold7 = false;
  242. bool onHoldShallow = false;
  243. bool onHoldDeep = false;
  244.  
  245. void setup() {
  246.   Serial.begin(115200);
  247.  
  248.   pinMode(SWITCHSHALLOW, INPUT_PULLUP);
  249.   pinMode(SWITCHDEEP,    INPUT_PULLUP);
  250.  
  251.   pinMode(OUTPUT1,       OUTPUT);
  252.   pinMode(OUTPUT2,       OUTPUT);
  253.   pinMode(OUTPUT3,       OUTPUT);
  254.   pinMode(OUTPUT4,       OUTPUT);
  255.   pinMode(OUTPUT5,       OUTPUT);
  256.   pinMode(OUTPUT6,       OUTPUT);
  257.   pinMode(OUTPUT7,       OUTPUT);
  258.   pinMode(OUTPUT8,       OUTPUT);
  259.   pinMode(OUTPUT9,       OUTPUT);
  260.   pinMode(OUTPUT10,      OUTPUT);
  261.   pinMode(OUTPUT11,      OUTPUT);
  262.   pinMode(OUTPUT12,      OUTPUT);
  263.   pinMode(OUTPUT13,      OUTPUT);
  264.   digitalWrite(OUTPUT1,  LOW);
  265.   digitalWrite(OUTPUT2,  LOW);
  266.   digitalWrite(OUTPUT3,  LOW);
  267.   digitalWrite(OUTPUT4,  LOW);
  268.   digitalWrite(OUTPUT5,  LOW);
  269.   digitalWrite(OUTPUT6,  LOW);
  270.   digitalWrite(OUTPUT7,  LOW);
  271.   digitalWrite(OUTPUT8,  LOW);
  272.   digitalWrite(OUTPUT9,  LOW);
  273.   digitalWrite(OUTPUT10, LOW);
  274.   digitalWrite(OUTPUT11, LOW);
  275.   digitalWrite(OUTPUT12, LOW);
  276.   digitalWrite(OUTPUT13, LOW);
  277.  
  278.   clearArray(collectedPattern, ARRAYLENGTH);
  279.   index = 0;
  280.   Serial.println("Begin");
  281. }
  282.  
  283. void cleanArray(unsigned int arrayIn[], unsigned int arrayOut[], unsigned int numItems) {
  284.   // produce a version of the array that has the first element removed,
  285.   // and checkForMatchesTimerExpired event time added to the subsequent time leading
  286.   // up to another button event
  287.   clearArray(arrayOut, ARRAYLENGTH);
  288.   unsigned int iIn = 1;
  289.   unsigned int iOut = 0;
  290.   while (iIn < numItems) {
  291.     if ( (iIn % 2) == 0) { // if iIn is even contains times
  292.       arrayOut[iOut] = arrayIn[iIn];
  293.       iIn++;
  294.       iOut++;
  295.     }
  296.     else { // if iIn is odd contains events
  297.       if ( arrayIn[iIn] == checkForMatchesTimerExpired && arrayIn[iIn + 1] != 0 && iIn > 1 && iIn < (numItems - 1)) {
  298.         // if a timer expired event is in the middle of the array,
  299.         // combine the time of expired event with time of next event
  300.         // and remove the timer expired event
  301.         arrayOut[iOut - 1] = arrayIn[iIn - 1] + arrayIn[iIn + 1];
  302.         iIn = iIn + 2;
  303.       }
  304.       else {
  305.         arrayOut[iOut] = arrayIn[iIn];
  306.         iIn++;
  307.         iOut++;
  308.       }
  309.     }
  310.   }
  311. }
  312.  
  313. bool mapAndCompareArray(unsigned int arrayIn[], unsigned int arrayMap[], const unsigned int arrayComp[], unsigned int numItems) {
  314.   // produce a version of the cleaned array that has the timings mapped to a range
  315.   // go through the cleaned array and re-range the times and get max time
  316.   unsigned int i = 0;
  317.   unsigned int maxTime = 0;
  318.   while (i < numItems) { // copy array contents, get max time for mapping,
  319.     // and insert 999 for times that should be ignored
  320.     arrayMap[i] = arrayIn[i];
  321.     if ( (i % 2) == 1) { // if i is odd contains times
  322.       if (arrayMap[i] == 999) { // if collected pattern array has time 999 in any
  323.         // position, tweak it so it is not skipped in the mapping
  324.         arrayMap[i] == 998;
  325.       }
  326.       if (pgm_read_word_near(&arrayComp[i]) == 999) { // special position where we need to ignore timing
  327.         arrayMap[i] = 999;
  328.       }
  329.       else if (arrayMap[i] > maxTime) {
  330.         maxTime = arrayMap[i];
  331.       }
  332.     }
  333.     i++;
  334.   }
  335.   // re-range all the times that are between 0 and max time
  336.   // to be between 0 and 100
  337.   i = 0;
  338.   while (i < numItems) {
  339.     if ( (i % 2) == 1) { // if i is odd contains times
  340.       if (arrayMap[i] != 999) {
  341.         arrayMap[i] = map(arrayMap[i], 0, maxTime, 0, 100);
  342.         if (arrayIn[i] != 0 && arrayMap[i] == 0) {
  343.           arrayMap[i] = 1;
  344.         }
  345.       }
  346.     }
  347.     i++;
  348.   }
  349.  
  350.   // compare arrays up to the end or the first 0 of arrays
  351.   // accept similarities of timing
  352.   // instead of requiring the timing to be exactly the same
  353.   bool same = true;
  354.   unsigned int minVal;
  355.   unsigned int maxVal;
  356.   i = 0;
  357.   while (i < numItems && same && ! (arrayMap[i] == 0 && pgm_read_word_near(&arrayComp[i]) == 0)) {
  358.     if ( (i % 2) == 1) { // if i is odd contains times
  359.       if (arrayMap[i] > ERRORPERCENT) {
  360.         minVal = arrayMap[i] - ERRORPERCENT;
  361.       }
  362.       else {
  363.         minVal = 1;
  364.       }
  365.       maxVal = arrayMap[i] + ERRORPERCENT;
  366.       if (pgm_read_word_near(&arrayComp[i]) >= minVal && pgm_read_word_near(&arrayComp[i]) <= maxVal) {
  367.         same = true;
  368.       }
  369.       else {
  370.         same = false;
  371.       }
  372.     }
  373.     else { // i is even and this element contains event
  374.       same = arrayMap[i] == pgm_read_word_near(&arrayComp[i]);
  375.     }
  376.     i++;
  377.   }
  378.   return same;
  379. }
  380.  
  381. void printFormattedArray(unsigned int arrayIn[], unsigned int numItems) {
  382.   // print array elements up to the end or the first 0
  383.   Serial.print("{");
  384.   unsigned int i = 0;
  385.   while (i < numItems) {
  386.     Serial.print(arrayIn[i]);
  387.     i++;
  388.     if (i == numItems)
  389.       Serial.println("}");
  390.     else
  391.       Serial.print(",");
  392.   }
  393. }
  394.  
  395. void clearArray(unsigned int arrayA[], unsigned int numItems) {
  396.   unsigned int i = 0;
  397.   while (i < numItems) {
  398.     arrayA[i] = 0;
  399.     i++;
  400.   }
  401.   // comment: = we only want to clear the index when
  402.   // clearing the collectedPattern array,
  403.   // not the other arrays
  404. }
  405.  
  406. void appendToArray(unsigned int arrayA[], unsigned int numItems, unsigned int value) {
  407.   if (index < numItems) {
  408.     arrayA[index] = value;
  409.     index++;
  410.   }
  411. }
  412.  
  413. void loop() {
  414.  
  415.   //Read and debounce switches.
  416.   bool reading1 = ! digitalRead(SWITCHSHALLOW);
  417.   bool reading2 = digitalRead(SWITCHDEEP);
  418.  
  419.   // check to see if you just pressed the button and reset timer
  420.   if (reading1 != lastButtonState1) {
  421.     lastDebounceTime1 = millis();
  422.   }
  423.   if ((millis() - lastDebounceTime1) > debounceDelay) {
  424.     // whatever the reading is at, it's been there for longer than the debounce
  425.     if (reading1 != buttonState1) {
  426.       buttonState1 = reading1;
  427.       buttonChange1 = true;
  428.       digitalWrite(OUTPUT1, buttonState1);
  429.     }
  430.   }
  431.  
  432.   // check to see if you just pressed the button and reset timer
  433.   if (reading2 != lastButtonState2) {
  434.     lastDebounceTime2 = millis();
  435.   }
  436.   if ((millis() - lastDebounceTime2) > debounceDelay) {
  437.     // whatever the reading is at, it's been there for longer than the debounce
  438.     if (reading2 != buttonState2) {
  439.       buttonState2 = reading2;
  440.       buttonChange2 = true;
  441.       digitalWrite(OUTPUT2, buttonState2);
  442.     }
  443.   }
  444.  
  445.   // check for changes of switch states and reset timers
  446.   if ( buttonChange1 ) {
  447.     buttonChange1 = false;
  448.     unsigned long diffmilli = millis() - resetArrayTimer;
  449.     if (diffmilli > 65000) {
  450.       diffmilli = 65000;
  451.     }
  452.     unsigned int diffmillint = (unsigned int) diffmilli;
  453.     appendToArray(collectedPattern, ARRAYLENGTH, diffmillint);
  454.     if ( buttonState1 ) {
  455.       appendToArray(collectedPattern, ARRAYLENGTH, SwitchShallowPressed);
  456.     }
  457.     else {
  458.       appendToArray(collectedPattern, ARRAYLENGTH, SwitchShallowReleased);
  459.     }
  460.     checkForMatchesTimerCounted = false;
  461.     resetArrayTimerCounted = false;
  462.     checkForMatchesTimer = millis();
  463.     resetArrayTimer = millis();
  464.   }
  465.   else if ( buttonChange2 ) {
  466.     buttonChange2 = false;
  467.     unsigned long diffmilli = millis() - resetArrayTimer;
  468.     if (diffmilli > 65000) {
  469.       diffmilli = 65000;
  470.     }
  471.     unsigned int diffmillint = (unsigned int) diffmilli;
  472.     appendToArray(collectedPattern, ARRAYLENGTH, diffmillint);
  473.     if ( buttonState2 ) {
  474.       appendToArray(collectedPattern, ARRAYLENGTH, SwitchDeepPressed);
  475.     }
  476.     else {
  477.       appendToArray(collectedPattern, ARRAYLENGTH, SwitchDeepReleased);
  478.     }
  479.     checkForMatchesTimerCounted = false;
  480.     resetArrayTimerCounted = false;
  481.     checkForMatchesTimer = millis();
  482.     resetArrayTimer = millis();
  483.   }
  484.  
  485.   // look for timers expired
  486.   // checkForMatchesTimer checks the collectedPattern array for matches
  487.   // against stored patterns 900 ms after the latest button activity
  488.   if ((millis() - checkForMatchesTimer) > checkForMatchesTimerDuration && checkForMatchesTimerCounted == false) {
  489.     checkForMatchesTimerCounted = true;
  490.     unsigned long diffmilli = millis() - checkForMatchesTimer;
  491.     if (diffmilli > 65000) {
  492.       diffmilli = 65000;
  493.     }
  494.     unsigned int diffmillint = (unsigned int) diffmilli;
  495.     appendToArray(collectedPattern, ARRAYLENGTH, diffmillint);
  496.     appendToArray(collectedPattern, ARRAYLENGTH, checkForMatchesTimerExpired);
  497.  
  498.     // if the checkForMatchesTimer expired we
  499.     //  want to execute the following code
  500.  
  501.     cleanArray(collectedPattern, collectedPatternCleaned, ARRAYLENGTH);
  502.     // step through patternTable and look for a match of
  503.     // cleaned collected pattern against patterns in progmem
  504.     // and exit on first match with index number set to the
  505.     // matched pattern
  506.     for (patternIndex = 0; patternIndex < NUMPATTERNS; patternIndex++) {
  507.       if (mapAndCompareArray(collectedPatternCleaned, collectedPatternMapped, pgm_read_word_near(&(patternTable[patternIndex])), ARRAYLENGTH)) {
  508.         break;
  509.       }
  510.     }
  511.  
  512.     // use the index number of the matched pattern to do an
  513.     // action
  514.     switch (patternIndex) {
  515.       case 0:
  516.       case 1:
  517.         onHoldShallow = true;
  518.         onHoldDeep = true;
  519.         digitalWrite(OUTPUT3,  HIGH);
  520.         digitalWrite(OUTPUT4,  HIGH);
  521.         Serial.print("slow-press-and-hold ");
  522.         Serial.println("onHoldShallow and onHoldDeep turned on");
  523.         break;
  524.  
  525.       case 2:
  526.         onHold5 = true;
  527.         Serial.print("fastPressAndHold ");
  528.         Serial.println("onHold5 turned on");
  529.         digitalWrite(OUTPUT5,  HIGH);
  530.         break;
  531.  
  532.       case 3:
  533.       case 4:
  534.         onHold6 = true;
  535.         Serial.print("dit-dah-and-hold ");
  536.         Serial.println("onHold6 turned on");
  537.         digitalWrite(OUTPUT6,  HIGH);
  538.         break;
  539.  
  540.       case 5:
  541.       case 6:
  542.         onHold7 = true;
  543.         Serial.print("dit-dit-dah-and-hold ");
  544.         Serial.println("onHold7 turned on");
  545.         digitalWrite(OUTPUT7,  HIGH);
  546.         break;
  547.  
  548.       case 7:
  549.       case 8:
  550.         // flip OUTPUT8
  551.         digitalWrite(OUTPUT8,  !digitalRead(OUTPUT8));
  552.         Serial.println("dit");
  553.         break;
  554.  
  555.       case 9:
  556.       case 10:
  557.         // turn on OUTPUT9 and set a timer to turn it off in 1 second
  558.         digitalWrite(OUTPUT9,  HIGH);
  559.         output9Timer = millis();
  560.         output9TimerDuration = 1000;
  561.         output9TimerCounted = false;
  562.         Serial.println("dit-dit");
  563.         break;
  564.  
  565.       case 11:
  566.       case 12:
  567.         // turn on OUTPUT10 and set a timer to turn it off in 2 second
  568.         digitalWrite(OUTPUT10,  HIGH);
  569.         output10Timer = millis();
  570.         output10TimerDuration = 2000;
  571.         output10TimerCounted = false;
  572.         Serial.println("dit-dit-dit");
  573.         break;
  574.  
  575.       case 13:
  576.       case 14:
  577.         // flip OUTPUT11
  578.         digitalWrite(OUTPUT11,  !digitalRead(OUTPUT11));
  579.         Serial.println("dah-dit");
  580.         break;
  581.  
  582.       case 15:
  583.       case 16:
  584.         // flip OUTPUT12
  585.         digitalWrite(OUTPUT12,  !digitalRead(OUTPUT12));
  586.         Serial.println("dah-dit-dit");
  587.         break;
  588.  
  589.       case 17:
  590.       case 18:
  591.       case 19:
  592.         // flip OUTPUT13
  593.         digitalWrite(OUTPUT13,  !digitalRead(OUTPUT13));
  594.         Serial.println("dit-dah-dit");
  595.         break;
  596.  
  597.       case NUMPATTERNS:
  598.         Serial.println("no match found");
  599.         printFormattedArray(collectedPatternMapped, ARRAYLENGTH);
  600.         break;
  601.     }
  602.   }
  603.  
  604.   if ((millis() - resetArrayTimer) > resetArrayTimerDuration && resetArrayTimerCounted == false) {
  605.     // If a button is depressed, the longest timer expired event is
  606.     // not used.   This is because this is where we clear the collected
  607.     // pattern array, and we don't want to do that if extended events
  608.     // may occur with button depressed.  Those events may go on until
  609.     // the button is released.
  610.     if ( buttonState1 || buttonState2 ) {
  611.       resetArrayTimerCounted = true;
  612.     }
  613.     else {
  614.       resetArrayTimerCounted = true;
  615.       // clear out the collected pattern array and start the index
  616.       // back to 0, waiting for the first event to be added to it.
  617.       clearArray(collectedPattern, ARRAYLENGTH);
  618.       index = 0;
  619.     }
  620.   }
  621.  
  622.   // turn off OUTPUT9 if it has been on for a while
  623.   if ((millis() - output9Timer) > output9TimerDuration && output9TimerCounted == false) {
  624.     output9TimerCounted = true;
  625.     digitalWrite(OUTPUT9,  LOW);
  626.   }
  627.  
  628.   // turn off OUTPUT10 if it has been on for a while
  629.   if ((millis() - output10Timer) > output10TimerDuration && output10TimerCounted == false) {
  630.     output10TimerCounted = true;
  631.     digitalWrite(OUTPUT10,  LOW);
  632.   }
  633.  
  634.   // look for actions that need to be taken as soon as button is released
  635.   if ( ! buttonState1 && ! buttonState2 && onHold5) {
  636.     onHold5 = false;
  637.     Serial.println("onHold5 turned off");
  638.     digitalWrite(OUTPUT5,  LOW);
  639.     // clear out the collected pattern array and start the index
  640.     // back to 0, waiting for the first event to be added to it.
  641.     // and stop looking for timer expirations
  642.     checkForMatchesTimerCounted = true;
  643.     resetArrayTimerCounted = true;
  644.     clearArray(collectedPattern, ARRAYLENGTH);
  645.     index = 0;
  646.   }
  647.   if ( ! buttonState1 && ! buttonState2 && onHold6) {
  648.     onHold6 = false;
  649.     Serial.println("onHold6 turned off");
  650.     digitalWrite(OUTPUT6,  LOW);
  651.     // clear out the collected pattern array and start the index
  652.     // back to 0, waiting for the first event to be added to it.
  653.     // and stop looking for timer expirations
  654.     checkForMatchesTimerCounted = true;
  655.     resetArrayTimerCounted = true;
  656.     clearArray(collectedPattern, ARRAYLENGTH);
  657.     index = 0;
  658.   }
  659.   if ( ! buttonState1 && ! buttonState2 && onHold7) {
  660.     onHold7 = false;
  661.     Serial.println("onHold7 turned off");
  662.     digitalWrite(OUTPUT7,  LOW);
  663.     // clear out the collected pattern array and start the index
  664.     // back to 0, waiting for the first event to be added to it.
  665.     // and stop looking for timer expirations
  666.     checkForMatchesTimerCounted = true;
  667.     resetArrayTimerCounted = true;
  668.     clearArray(collectedPattern, ARRAYLENGTH);
  669.     index = 0;
  670.   }
  671.   // onHoldShallow and onHoldDeep is regulating the releasing
  672.   // of button for pass through of cruise control setting
  673.   if ( ! buttonState1 && ! buttonState2 && onHoldShallow) {
  674.     onHoldShallow = false;
  675.     digitalWrite(OUTPUT3,  LOW);
  676.     Serial.println("onHoldShallow turned off");
  677.     // clear out the collected pattern array and start the index
  678.     // back to 0, waiting for the first event to be added to it.
  679.     // and stop looking for timer expirations
  680.     checkForMatchesTimerCounted = true;
  681.     resetArrayTimerCounted = true;
  682.     clearArray(collectedPattern, ARRAYLENGTH);
  683.     index = 0;
  684.   }
  685.   if ( buttonState1 && ! buttonState2 && onHoldDeep) {
  686.     onHoldDeep = false;
  687.     digitalWrite(OUTPUT4,  LOW);
  688.     Serial.println("onHoldDeep turned off");
  689.     // clear out the collected pattern array and start the index
  690.     // back to 0, waiting for the first event to be added to it.
  691.     // and stop looking for timer expirations
  692.     checkForMatchesTimerCounted = true;
  693.     resetArrayTimerCounted = true;
  694.     clearArray(collectedPattern, ARRAYLENGTH);
  695.     index = 0;
  696.   }
  697.  
  698.   // more debounce code
  699.   lastButtonState1 = reading1;
  700.   lastButtonState2 = reading2;
  701. }  // end of loop
Add Comment
Please, Sign In to add comment