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