Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: MMA8451Q_ext mbed
Revision 0:ac4e452b3199, committed 2013-03-15
- Comitter:
- maclobdell
- Date:
- Fri Mar 15 19:06:22 2013 +0000
- Commit message:
- public release
Changed in this revision
diff -r 000000000000 -r ac4e452b3199 MMA8451Q_ext.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MMA8451Q_ext.lib Fri Mar 15 19:06:22 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/maclobdell/code/MMA8451Q_ext/#018aea85c0db
diff -r 000000000000 -r ac4e452b3199 main.cpp
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Fri Mar 15 19:06:22 2013 +0000
@@ -0,0 +1,348 @@
+#include "mbed.h"
+#include "MMA8451Q.h"
+
+#define MMA8451_I2C_ADDRESS (0x1d<<1)
+
+/* Secret Knock Demo for FRDM-KL25Z by Mac Lobdell */
+/* Several bits and pieces taken from code by Steve Hoefer (http://grathio.com) under a creative commons share-alike license */
+/* Revison 1.0
+/* Programming not supported yet - only knows "shave and a hair cut, two bits" (or another pre-set sequence if set in secretCode variable initialization) */
+
+void INT2ISR(void);
+void INT1ISR(void);
+void d2ISR(void);
+int validateKnock(void);
+void triggerSuccessfulAction(void);
+void triggerFailedAction(void);
+int map(int x, int in_min, int in_max, int out_min, int out_max);
+
+Serial pc(USBTX,USBRX);
+MMA8451Q acc(PTE25, PTE24, MMA8451_I2C_ADDRESS);
+DigitalOut rled(LED_RED);
+DigitalOut gled(LED_GREEN);
+DigitalOut bled(LED_BLUE);
+
+DigitalOut d2(PTD4);
+Timer timer;
+
+const int maximumKnocks = 8; // Maximum number of knocks to listen for.
+int secretCode[maximumKnocks] = {
+ 50, 25, 25, 50, 100, 50, 0, 0 }; //, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; // Initial setup: "Shave and a Hair Cut, two bits." 100=full note, 50=half note, 25=quarter note, etc.
+int secretKnockMax = 6;
+const int rejectValue = 30; // If an individual knock is off by this percentage of a knock we ignore. (30 is pretty lose. 10 is strict)
+const int averageRejectValue = 20; // If the average timing of the knocks is off by this percent we ignore. (20 is pretty lose, 10 is strict.)
+int knockTime[maximumKnocks]; // When someone knocks this array fills with delays between knocks. (A correct knock looks a lot like the line above).
+int nKnockTime[maximumKnocks];
+int knocking = 0;
+int counter;
+int knockCount = 0; //starts at 0 for first knock
+int i = 0;
+int programButtonPressed = false;
+int startTime;
+int dummyKnock = 1;
+int unlocked = 0;
+
+int main(void) {
+
+ DigitalIn int1(PTA14); //data ready interrupt
+ int1.mode(PullUp);
+ DigitalIn int2(PTA15); //tap or Portrat/Landscape interrupt
+ int2.mode(PullUp);
+
+ /* initialize all variables */
+ knocking = 0;
+ counter = 0;
+ knockCount = 0;
+ startTime = 0;
+ dummyKnock = 1;
+ unlocked = 0;
+ for(i = 0; i<maximumKnocks; i++)
+ {
+ knockTime[i] = 0;
+ nKnockTime[i] = 0;
+ }
+ rled = 1; //off
+ gled = 0; //on
+ bled = 1; //off
+
+ //To Do - need to check if programming
+ //capacitive touch slider swipe?
+ if (programButtonPressed==true){
+ for (i=0;i<3;i++){
+ wait_ms(100);
+ gled = 0;
+ bled = 0;
+ wait_ms(100);
+ gled = 1;
+ bled = 1;
+ }
+ }
+
+ //enable interrupts
+ InterruptIn int1i(PTA14);
+ int1i.fall(&INT1ISR);
+ InterruptIn int2i(PTA15);
+ int2i.fall(&INT2ISR);
+
+ while(1)
+ {
+ //just hang out and wait for interrupts
+ if(knocking == 1)
+ {
+ counter++; //increment here, it will start over to 0 if knock happens in ISR
+ bled = 0; //blue on
+ gled = 1; //green off
+ wait_ms(10); //wait 10 ms
+ if ((counter > 1000) || ((knockCount) >= secretKnockMax )) //timeout after 100*10ms = 1 sec, or if max knocks ocurred
+ {
+ timer.stop();
+
+ //report what happened
+ if(counter > 100)
+ {
+ pc.printf("timout\n\r");
+ }else
+ {
+ pc.printf("max knocks\n\r");
+ }
+
+ /* check if secret code */
+ if (validateKnock() == true){
+ triggerSuccessfulAction();
+ unlocked = 1;
+ }
+ else {
+ triggerFailedAction();
+ unlocked = 0;
+ }
+
+ /* re-initialize all variables */
+ counter = 0;
+ knocking = 0;
+ knockCount = 0;
+ unlocked = 0;
+ for(i = 0; i<maximumKnocks; i++)
+ {
+ knockTime[i] = 0;
+ }
+ rled = 1; //off
+ gled = 0; //on
+ bled = 1; //off
+
+
+ }
+
+ }
+ }
+
+
+}
+void d2ISR(void)
+{
+ pc.printf("d2 ISR\n\r");
+
+}
+void INT1ISR(void)
+{
+ /*Acceleration data Ready ISR */
+
+ // rled = 1.0 - abs(acc.getAccX());
+ // gled = 1.0 - abs(acc.getAccY());
+ // bled = 1.0 - abs(acc.getAccZ());
+}
+
+void INT2ISR(void)
+{
+ /* tap occurred - make sure only single taps in one direction are enabled */
+
+ uint8_t dummy;
+
+ dummy = acc.tapSource(); //seems like you need to read the source to clear the interrupt
+
+// pc.printf("tap isr\n\r");
+
+ //if(dummyKnock == 1)
+ //{
+ // //always get a bad knock on reset
+ // dummyKnock = 0;
+ // pc.printf("dummy knock \n");
+ //}else
+ {
+
+
+ // pc.printf("Tap \n");
+ counter = 0; //reset the timeout counter
+
+ if(knocking ==0)
+ {
+ //this is the first knock
+ pc.printf("first knock\n\r");
+ knockCount = 0;
+ knocking = 1;
+ pc.printf("start timer\n\r");
+ timer.start();
+ timer.reset();
+ startTime = timer.read_ms();
+
+ }else if(knocking == 1)
+ {
+ //this is not the first knock
+ pc.printf("not first knock\n\r");
+ int now;
+ now = timer.read_ms();
+ pc.printf("startTime = %d\n\r",startTime);
+ pc.printf("now = %d\n\r",now);
+ knockTime[knockCount] = (now - startTime);
+ pc.printf("knockTime[knockCount] : %d\n\r",knockTime[knockCount]);
+
+ knockCount++;
+ pc.printf("knockCount : %d\n\r",knockCount);
+
+ startTime = now; //start time for next knock period
+
+
+
+ }
+
+ }
+
+}
+
+
+// We got a good knock, so do something!
+void triggerSuccessfulAction(){
+ pc.printf("Success!\n\r");
+
+ rled = 1; //off
+ gled = 0; //on
+ bled = 1; //off
+
+ for (int i=0;i<16;i++){
+ gled = 0;
+ wait_ms(100);
+ gled = 1;
+ wait_ms(100);
+ }
+
+}
+
+// We didn't like the knock. Indicate displeasure.
+void triggerFailedAction(){
+ pc.printf("Secret knock failed\n");
+ rled = 0; //on
+ gled = 1; //off
+ bled = 1; //off
+
+ for (int i=0;i<16;i++){
+ rled = 0;
+ wait_ms(100);
+ rled = 1;
+ wait_ms(100);
+ }
+}
+
+// Checks if our knock matches the secret.
+// Returns true if it's a good knock, false if it's not.
+int validateKnock(){
+ int i=0;
+ // Simplest check first: Did we get the right number of knocks?
+ int currentKnockCount = 0;
+ int secretKnockCount = 0;
+ int maxKnockInterval = 0; // We use this later to normalize the times.
+
+ int codeFound=true;
+ int totaltimeDifferences=0;
+ int timeDiff=0;
+
+ pc.printf("validating knock sequence \n\r");
+
+
+ for (i=0;i<maximumKnocks;i++){
+ if (knockTime[i] > 0){
+ currentKnockCount++;
+ }
+ if (secretCode[i] > 0){
+ secretKnockCount++;
+ }
+
+ if (knockTime[i] > maxKnockInterval){ // Collect normalization data while we're looping.
+ maxKnockInterval = knockTime[i];
+ }
+ }
+ pc.printf("max knock interval: \n\r",maxKnockInterval);
+
+ // If we're recording a new knock, save the relevant info and get out of here.
+ /*if (programButtonPressed==true){
+ for (i=0;i<maximumKnocks;i++){ // Normalize the knock timing
+ secretCode[i]= map(knockTime[i],0, maxKnockInterval, 0, 100);
+ }
+ // And flash the lights in the recorded pattern to let us know it's been programmed.
+ bled = 0;
+ rled = 0;
+ wait_ms(750);
+
+ //Start playing back the knocks
+ bled = 1;
+ rled = 1;
+ wait_ms(40);
+ for (i = 0; i < maximumKnocks ; i++){
+ bled = 0;
+ rled = 0;
+
+ if (programButtonPressed==true){ // Only turn it on if there's a delay
+ if (secretCode[i] > 0){
+ wait_ms(map(secretCode[i],0, 100, 0, maxKnockInterval)); // Expand the time back out to what it was. Roughly.
+ bled = 1;
+ rled = 1;
+ }
+ }
+ wait_ms(40);
+ bled = 0;
+ rled = 0;
+ }
+ return false; // We don't do anything when we are recording a new knock.
+ }
+*/
+ pc.printf("currentKnockCount: %d secretKnockCount %d\n\r",currentKnockCount,secretKnockCount);
+
+ if (currentKnockCount != secretKnockCount){
+ pc.printf("wrong number of knocks\n\r");
+ return false; // Return false if the number of knocks are wrong.
+ }
+
+ /* Now we compare the relative intervals of our knocks, not the absolute time between them.
+ (ie: if you do the same pattern slow or fast it should still work.)
+ This makes it less picky, which does make it less secure but also makes it
+ less of a pain to use if you're tempo is a little slow or fast.
+ */
+ for (i=0;i<maximumKnocks;i++){
+ nKnockTime[i] = 0; //reinitialize
+ }
+ for (i=0;i<maximumKnocks;i++){ // Normalize the times
+ nKnockTime[i]= map(knockTime[i],0, maxKnockInterval, 0, 100);
+ pc.printf("knock time: %d, normalized knock time: %d, secret code time %d \n\r",knockTime[i], nKnockTime[i], secretCode[i]);
+ timeDiff = abs(nKnockTime[i]-secretCode[i]);
+ if (timeDiff > rejectValue){ // Individual value too far out of whack
+ codeFound=false;
+ }
+ totaltimeDifferences += timeDiff;
+ }
+ // It can also fail if the whole thing is too inaccurate.
+ if (totaltimeDifferences/secretKnockCount>averageRejectValue){
+ codeFound = false;
+ }
+
+ if (codeFound==false){
+ return false;
+ }
+ else {
+ return true;
+ }
+
+}
+
+
+int map(int x, int in_min, int in_max, int out_min, int out_max)
+{
+ return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
+}
\ No newline at end of file
diff -r 000000000000 -r ac4e452b3199 mbed.bld --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Fri Mar 15 19:06:22 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/5e5da4a5990b \ No newline at end of file