Andrew Shi / Mbed 2 deprecated Lab4

Dependencies:   mbed 4DGL-uLCD-SE PinDetect

Files at this revision

API Documentation at this revision

Comitter:
ashi31
Date:
Fri Oct 22 03:57:47 2021 +0000
Commit message:
Lab4

Changed in this revision

4DGL-uLCD-SE.lib Show annotated file Show diff for this revision Revisions of this file
Die.cpp Show annotated file Show diff for this revision Revisions of this file
Die.h Show annotated file Show diff for this revision Revisions of this file
FarkleGame.cpp Show annotated file Show diff for this revision Revisions of this file
FarkleGame.h Show annotated file Show diff for this revision Revisions of this file
MMA8452.cpp Show annotated file Show diff for this revision Revisions of this file
MMA8452.h Show annotated file Show diff for this revision Revisions of this file
PinDetect.h Show annotated file Show diff for this revision Revisions of this file
PinDetect.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/4DGL-uLCD-SE.lib	Fri Oct 22 03:57:47 2021 +0000
@@ -0,0 +1,1 @@
+https://mbed.org/users/4180_1/code/4DGL-uLCD-SE/#e39a44de229a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Die.cpp	Fri Oct 22 03:57:47 2021 +0000
@@ -0,0 +1,140 @@
+#include "Die.h"
+
+#include <string>
+#include <iostream>
+
+#include <stdlib.h>     /* srand, rand */
+#include <time.h>       /* time */
+
+#define WHITE 0xFFFFFF
+
+using namespace std;
+
+//Constructors
+Die::Die(){
+    val = 1;
+}
+
+Die::Die(int v){
+    if((v > 0) && (v < 7)){
+        val = v;
+    }
+    else{
+        val = 1;
+    }
+}
+
+//Public Methods
+void Die::rollDie(){
+    
+    val = rand()%6+1;
+}
+
+//6 draw functions
+void Die::draw1(int pos, uLCD_4DGL& scr){
+    int ycent = 42*(((pos-1)/3)+1)-21;
+    int xcent = 42*(((pos-1)%3)+1)-21;
+    
+    int width = 20;
+    
+    int rad = 5;
+    
+    scr.rectangle(xcent-width, ycent-width, xcent+width, ycent+width, WHITE);
+    scr.filled_circle(xcent,ycent,rad,WHITE);
+}
+
+void Die::draw2(int pos, uLCD_4DGL& scr){
+    int ycent = 42*(((pos-1)/3)+1)-21;
+    int xcent = 42*(((pos-1)%3)+1)-21;
+    
+    int width = 20;
+    
+    int rad = 5;
+    
+    scr.rectangle(xcent-width, ycent-width, xcent+width, ycent+width, WHITE);
+    scr.filled_circle(xcent+12,ycent+12,rad,WHITE);
+    scr.filled_circle(xcent-12,ycent-12,rad,WHITE);
+}
+
+void Die::draw3(int pos, uLCD_4DGL& scr){
+    int ycent = 42*(((pos-1)/3)+1)-21;
+    int xcent = 42*(((pos-1)%3)+1)-21;
+    
+    int width = 20;
+    
+    int rad = 5;
+    
+    scr.rectangle(xcent-width, ycent-width, xcent+width, ycent+width, WHITE);
+    scr.filled_circle(xcent+12,ycent+12,rad,WHITE);
+    scr.filled_circle(xcent,ycent,rad,WHITE);
+    scr.filled_circle(xcent-12,ycent-12,rad,WHITE);
+}
+
+void Die::draw4(int pos, uLCD_4DGL& scr){
+    int ycent = 42*(((pos-1)/3)+1)-21;
+    int xcent = 42*(((pos-1)%3)+1)-21;
+    
+    int width = 20;
+    
+    int rad = 5;
+    
+    scr.rectangle(xcent-width, ycent-width, xcent+width, ycent+width, WHITE);
+    scr.filled_circle(xcent+12,ycent+12,rad,WHITE);
+    scr.filled_circle(xcent+12,ycent-12,rad,WHITE);
+    scr.filled_circle(xcent-12,ycent+12,rad,WHITE);
+    scr.filled_circle(xcent-12,ycent-12,rad,WHITE);
+}
+
+void Die::draw5(int pos, uLCD_4DGL& scr){
+    int ycent = 42*(((pos-1)/3)+1)-21;
+    int xcent = 42*(((pos-1)%3)+1)-21;
+    
+    int width = 20;
+    
+    int rad = 5;
+    
+    scr.rectangle(xcent-width, ycent-width, xcent+width, ycent+width, WHITE);
+    scr.filled_circle(xcent,ycent,rad,WHITE);
+    scr.filled_circle(xcent+12,ycent+12,rad,WHITE);
+    scr.filled_circle(xcent+12,ycent-12,rad,WHITE);
+    scr.filled_circle(xcent-12,ycent+12,rad,WHITE);
+    scr.filled_circle(xcent-12,ycent-12,rad,WHITE);
+}
+
+void Die::draw6(int pos, uLCD_4DGL& scr){
+    int ycent = 42*(((pos-1)/3)+1)-21;
+    int xcent = 42*(((pos-1)%3)+1)-21;
+    
+    int width = 20;
+    
+    int rad = 5;
+    
+    scr.rectangle(xcent-width, ycent-width, xcent+width, ycent+width, WHITE);
+    scr.filled_circle(xcent-12,ycent,rad,WHITE);
+    scr.filled_circle(xcent+12,ycent,rad,WHITE);
+    scr.filled_circle(xcent+12,ycent+12,rad,WHITE);
+    scr.filled_circle(xcent+12,ycent-12,rad,WHITE);
+    scr.filled_circle(xcent-12,ycent+12,rad,WHITE);
+    scr.filled_circle(xcent-12,ycent-12,rad,WHITE);
+}
+
+//display Die based on value
+void Die::displayDie(int position, uLCD_4DGL& screen){
+       if(val == 1){draw1(position,screen);}
+       if(val == 2){draw2(position,screen);}
+       if(val == 3){draw3(position,screen);}
+       if(val == 4){draw4(position,screen);}
+       if(val == 5){draw5(position,screen);}
+       if(val == 6){draw6(position,screen);}
+}
+
+
+
+//S&G
+void Die::setVal(int v){
+    val = v;
+}
+
+int Die::getVal(){
+    return val;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Die.h	Fri Oct 22 03:57:47 2021 +0000
@@ -0,0 +1,41 @@
+#ifndef DIE_H
+#define DIE_H
+
+#include "mbed.h"
+#include "uLCD_4DGL.h"
+
+#include <iostream>
+#include <string>
+
+using namespace std;
+
+class Die{
+    public:
+        //Constructor
+        Die();
+        Die(int v);
+        
+        //public methods
+        void rollDie();
+        
+        //draw methods
+        void draw1(int, uLCD_4DGL&);
+        void draw2(int, uLCD_4DGL&);
+        void draw3(int, uLCD_4DGL&);
+        void draw4(int, uLCD_4DGL&);
+        void draw5(int, uLCD_4DGL&);
+        void draw6(int, uLCD_4DGL&);
+        
+        //display drawings
+        void displayDie(int, uLCD_4DGL&);
+               
+        //val s&g
+        int getVal();
+        void setVal(int);
+        
+    private:
+        int val;
+};
+
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FarkleGame.cpp	Fri Oct 22 03:57:47 2021 +0000
@@ -0,0 +1,225 @@
+#include "Die.h"
+#include "FarkleGame.h"
+
+#include <string>
+#include <iostream>
+#include <sstream>
+
+using namespace std;
+
+//Constructors
+FarkleGame::FarkleGame(){
+    Die Dice[6];
+    int DiceVals[6];
+    
+    int turnScore = 0;
+    int rollScore = 0;
+    int farkles = 0;
+}
+
+//Method
+void FarkleGame::dispIntro(uLCD_4DGL& scr, int nd){
+    scr.cls();
+    scr.display_control(PORTRAIT);
+
+    scr.text_width(2);
+    scr.text_height(2);
+    scr.locate(0,1);
+    scr.printf("Shake\n");
+    scr.printf("Board\n");
+    scr.printf("------\n");
+    scr.printf("To\n");
+    scr.printf("Roll\n");
+    scr.printf("%d Dice", nd);
+}
+
+void FarkleGame::init(){
+    turnScore = 0;
+    rollScore = 0;
+    farkles = 0;
+}
+
+void FarkleGame::rollDice(){
+    for(int i = 0; i < 6; i++){
+        Dice[i].rollDie();
+    }
+}
+
+void FarkleGame::displayDice(uLCD_4DGL& scr, int nd){
+    
+    scr.cls();
+    scr.display_control(PORTRAIT);
+    
+    for(int i = 0; i < nd; i++){
+        Dice[i].displayDie(i+1, scr);
+    }
+    
+}
+
+void FarkleGame::loadVals(int nd){
+    for(int i = 0; i < 6; i++){
+        DiceVals[i] = 0;
+    }
+    for(int i = 0; i < nd; i++){
+        if(Dice[i].getVal() == 1){
+            DiceVals[0]++;
+        }else if(Dice[i].getVal() == 2){
+            DiceVals[1]++;
+        }else if(Dice[i].getVal() == 3){
+            DiceVals[2]++;
+        }else if(Dice[i].getVal() == 4){
+            DiceVals[3]++;
+        }else if(Dice[i].getVal() == 5){
+            DiceVals[4]++;
+        }else if(Dice[i].getVal() == 6){
+            DiceVals[5]++;
+        }
+    }    
+}
+
+int FarkleGame::calcScore(){
+    //Scores will be checked in descending order of value
+    
+    //check for 6
+    for(int i = 0; i < 6; i++){
+        if(DiceVals[i] == 6){
+            return 3000;
+        }
+    }
+    
+    //check for 2triplets
+    int tripCount = 0;
+    for(int i = 0; i < 6; i++){
+        if(DiceVals[i] == 3) tripCount++;
+    }
+    if(tripCount == 2){
+        return 2500;
+    }
+    
+    //check for 5
+    for(int i = 0; i < 6; i++){
+        if(DiceVals[i] == 5){
+            return 2000;
+        }
+    }
+    
+    //check for 123456
+    int singCount = 0;
+    for(int i = 0; i < 6; i++){
+        if(DiceVals[i] == 1) singCount++;
+    }
+    if(singCount == 6){
+        return 1500;
+    }
+    
+    //check for 3doubs
+    int doubCount = 0;
+    for(int i = 0; i < 6; i++){
+        if(DiceVals[i] == 2) doubCount++;
+    }
+    if(doubCount == 3){
+        return 1500;
+    }
+
+    //check for 4
+    for(int i = 0; i < 6; i++){
+        if(DiceVals[i] == 4){
+            return 1000;
+        }
+    }
+    
+    //check trips
+    if(tripCount == 1){
+        if(DiceVals[0] == 3){
+            return 1000;
+        }else if(DiceVals[5] == 3){
+            return 600;
+        }
+        else if(DiceVals[4] == 3){
+            return 500;
+        }else if(DiceVals[3] == 3){
+            return 400;
+        }else if(DiceVals[2] == 3){
+            return 300;
+        }else if(DiceVals[1] == 3){
+            return 200;
+        }
+    }
+    
+    //check 1
+    if(DiceVals[0] != 0){
+        return 100;
+    }
+    
+    //check 5
+    if(DiceVals[4] != 0){
+        return 50;
+    }
+
+    farkles++;
+
+    return 0;
+}
+
+void FarkleGame::updateScores(){
+    rollScore = calcScore();
+    turnScore += rollScore;
+    if(farkles > 0){
+        turnScore = 0;
+    }
+}
+
+void FarkleGame::dispFarkle(uLCD_4DGL& scr){
+    scr.text_width(2);
+    scr.text_height(2);
+    scr.locate(0,6);
+    
+    scr.printf("FARKLE!");
+}
+
+void FarkleGame::dispScore(uLCD_4DGL& scr){
+    scr.text_width(1);
+    scr.text_height(1);
+    scr.locate(0,11);
+    
+    scr.printf("\nThis Turn: %d\n", turnScore);
+    scr.printf("\nThis Roll: %d\n", rollScore);
+    //scr.printf("Val Counts: %d %d %d %d %d %d", DiceVals[0], DiceVals[1], DiceVals[2], DiceVals[3], DiceVals[4], DiceVals[5]);
+}
+
+void FarkleGame::dispTurn(uLCD_4DGL& scr){
+    scr.cls();
+    scr.display_control(PORTRAIT);
+
+    scr.text_width(2);
+    scr.text_height(2);
+    scr.locate(0,1);
+    scr.printf("Your\n");
+    scr.printf("Turn\n");
+    scr.printf("Score\n");
+    scr.printf("-----\n");
+    scr.printf("%d\n", turnScore);
+}
+
+void FarkleGame::scrnWipe(uLCD_4DGL& scr){
+    scr.cls();
+}
+
+bool FarkleGame::checkRoll(MMA8452& a){
+    double x = 0;
+    double y = 0;
+    double z = 0;
+    
+    a.readXYZGravity(&x,&y,&z);
+    
+    return (x > 0.5 || x < -0.5 || y > 0.5 || y < -0.5);
+}
+
+//S&G
+void FarkleGame::setDieVal(int pos, int v){
+    Dice[pos-1].setVal(v);
+}
+
+int FarkleGame::getDieVal(int pos){
+    return Dice[pos-1].getVal();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/FarkleGame.h	Fri Oct 22 03:57:47 2021 +0000
@@ -0,0 +1,50 @@
+#ifndef FARKLEGAME_H
+#define FARKLEGAME_H
+
+#include "Die.h"
+#include "MMA8452.h"
+
+#include <iostream>
+#include <string>
+
+using namespace std;
+
+class FarkleGame{
+    public:
+        //Constructor
+        FarkleGame();
+        
+        //Methods
+        void dispIntro(uLCD_4DGL&, int);
+        void init();
+        
+        //rolling/scoring methods
+        void rollDice();
+        void displayDice(uLCD_4DGL&, int);
+        void loadVals(int);
+        int calcScore();
+        void updateScores();
+        
+        //display methods
+        void dispFarkle(uLCD_4DGL&);
+        void dispScore(uLCD_4DGL&);
+        void dispTurn(uLCD_4DGL&);
+        void scrnWipe(uLCD_4DGL&);
+
+        //acc methods
+        bool checkRoll(MMA8452&);
+        
+        //S&G
+        int getDieVal(int);
+        void setDieVal(int, int);
+        
+    private:
+        Die Dice[6];
+        int DiceVals[6];
+        
+        int turnScore;
+        int rollScore;
+        int farkles;
+};
+
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MMA8452.cpp	Fri Oct 22 03:57:47 2021 +0000
@@ -0,0 +1,538 @@
+// Authors: Ashley Mills, Nicholas Herriot
+/* Copyright (c) 2013 Vodafone, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+ 
+#include "MMA8452.h"
+#include "mbed.h"
+ 
+#ifdef MMA8452_DEBUG
+// you need to define Serial pc(USBTX,USBRX) somewhere for the below line to make sense
+extern Serial pc;
+#define MMA8452_DBG(...) pc.printf(__VA_ARGS__); pc.printf("\r\n");
+#else
+#define MMA8452_DBG(...)
+#endif
+ 
+// Connect module at I2C address using I2C port pins sda and scl
+MMA8452::MMA8452(PinName sda, PinName scl, int frequency) : _i2c(sda, scl) , _frequency(frequency) {
+   MMA8452_DBG("Creating MMA8452");
+   
+   // set I2C frequency
+   _i2c.frequency(_frequency);
+   
+   // setup read and write addresses for convenience
+   _readAddress   = MMA8452_ADDRESS | 0x01;
+   _writeAddress  = MMA8452_ADDRESS & 0xFE;
+   
+   // set some defaults
+   _bitDepth = BIT_DEPTH_UNKNOWN;
+   setBitDepth(BIT_DEPTH_12);
+   _dynamicRange = DYNAMIC_RANGE_UNKNOWN;
+   setDynamicRange(DYNAMIC_RANGE_2G);
+   
+   MMA8452_DBG("Done");
+}
+ 
+ 
+// Destroys instance
+MMA8452::~MMA8452() {}
+ 
+// Setting the control register bit 1 to true to activate the MMA8452
+int MMA8452::activate() {
+    // perform write and return error code
+    return logicalORRegister(MMA8452_CTRL_REG_1,MMA8452_ACTIVE_MASK);
+}
+ 
+// Setting the control register bit 1 to 0 to standby the MMA8452
+int MMA8452::standby() {
+    // perform write and return error code
+    return logicalANDRegister(MMA8452_CTRL_REG_1,MMA8452_STANDBY_MASK);
+}
+ 
+// this reads a register, applies a bitmask with logical AND, sets a value with logical OR,
+// and optionally goes into and out of standby at the beginning and end of the function respectively
+int MMA8452::maskAndApplyRegister(char reg, char mask, char value, int toggleActivation) {
+   if(toggleActivation) {
+       if(standby()) {
+          return 1;
+       }
+   }
+   
+   // read from register
+   char oldValue = 0;
+   if(readRegister(reg,&oldValue)) {
+      return 1;
+   }
+   
+   // apply bitmask
+   oldValue &= mask;
+   
+   // set value
+   oldValue |= value;
+   
+   // write back to register
+   if(writeRegister(reg,oldValue)) {
+      return 1;
+   }
+   
+   if(toggleActivation) {
+       if(activate()) {
+          return 1;
+       }
+   }
+   return 0;
+}
+ 
+int MMA8452::setDynamicRange(DynamicRange range, int toggleActivation) {
+   _dynamicRange = range;
+   return maskAndApplyRegister(
+      MMA8452_XYZ_DATA_CFG,
+      MMA8452_DYNAMIC_RANGE_MASK,
+      range,
+      toggleActivation
+   );
+}
+ 
+int MMA8452::setDataRate(DataRateHz dataRate, int toggleActivation) {
+   return maskAndApplyRegister(
+       MMA8452_CTRL_REG_1,
+       MMA8452_DATA_RATE_MASK,
+       dataRate<<MMA8452_DATA_RATE_MASK_SHIFT,
+       toggleActivation
+   );
+}
+ 
+int MMA8452::setBitDepth(BitDepth depth,int toggleActivation) {
+   _bitDepth = depth;
+   return maskAndApplyRegister(
+      MMA8452_CTRL_REG_1,
+      MMA8452_BIT_DEPTH_MASK,
+      depth<<MMA8452_BIT_DEPTH_MASK_SHIFT,
+      toggleActivation
+   );
+}
+ 
+char MMA8452::getMaskedRegister(int addr, char mask) {
+   char rval = 0;
+   if(readRegister(addr,&rval)) {
+      return 0;
+   }
+   return (rval&mask);
+}
+ 
+int MMA8452::isXYZReady() {
+   return getMaskedRegister(MMA8452_STATUS,MMA8452_STATUS_ZYXDR_MASK)>0;
+}
+ 
+int MMA8452::isXReady() {
+   return getMaskedRegister(MMA8452_STATUS,MMA8452_STATUS_XDR_MASK)>0;
+}
+ 
+int MMA8452::isYReady() {
+   return getMaskedRegister(MMA8452_STATUS,MMA8452_STATUS_YDR_MASK)>0;
+}
+ 
+int MMA8452::isZReady() {
+   return getMaskedRegister(MMA8452_STATUS,MMA8452_STATUS_ZDR_MASK)>0;
+}
+ 
+ 
+int MMA8452::getDeviceID(char *dst) {
+   return readRegister(MMA8452_WHO_AM_I,dst);
+}
+ 
+int MMA8452::getStatus(char* dst) {
+   return readRegister(MMA8452_STATUS,dst);
+}
+ 
+MMA8452::DynamicRange MMA8452::getDynamicRange() {
+   char rval = 0;
+   if(readRegister(MMA8452_XYZ_DATA_CFG,&rval)) {
+      return MMA8452::DYNAMIC_RANGE_UNKNOWN;
+   }
+   rval &= (MMA8452_DYNAMIC_RANGE_MASK^0xFF);
+   return (MMA8452::DynamicRange)rval;
+}
+ 
+MMA8452::DataRateHz MMA8452::getDataRate() {
+   char rval = 0;
+   if(readRegister(MMA8452_CTRL_REG_1,&rval)) {
+      return MMA8452::RATE_UNKNOWN;
+   }
+   // logical AND with inverse of mask
+   rval = rval&(MMA8452_DATA_RATE_MASK^0xFF);
+   // shift back into position
+   rval >>= MMA8452_DATA_RATE_MASK_SHIFT;
+   return (MMA8452::DataRateHz)rval;
+}
+ 
+// Reads xyz
+int MMA8452::readXYZRaw(char *dst) {
+   if(_bitDepth==BIT_DEPTH_UNKNOWN) {
+      return 1;
+   }
+   int readLen = 3;
+   if(_bitDepth==BIT_DEPTH_12) {
+      readLen = 6;
+   }
+   return readRegister(MMA8452_OUT_X_MSB,dst,readLen);
+}
+ 
+int MMA8452::readXRaw(char *dst) {
+   if(_bitDepth==BIT_DEPTH_UNKNOWN) {
+      return 1;
+   }
+   int readLen = 1;
+   if(_bitDepth==BIT_DEPTH_12) {
+      readLen = 2;
+   }
+   return readRegister(MMA8452_OUT_X_MSB,dst,readLen);
+}
+ 
+int MMA8452::readYRaw(char *dst) {
+   if(_bitDepth==BIT_DEPTH_UNKNOWN) {
+      return 1;
+   }
+   int readLen = 1;
+   if(_bitDepth==BIT_DEPTH_12) {
+      readLen = 2;
+   }
+   return readRegister(MMA8452_OUT_Y_MSB,dst,readLen);
+}
+ 
+int MMA8452::readZRaw(char *dst) {
+   if(_bitDepth==BIT_DEPTH_UNKNOWN) {
+      return 1;
+   }
+   int readLen = 1;
+   if(_bitDepth==BIT_DEPTH_12) {
+      readLen = 2;
+   }
+   return readRegister(MMA8452_OUT_Z_MSB,dst,readLen);
+}
+ 
+int MMA8452::readXYZCounts(int *x, int *y, int *z) {
+   char buf[6];
+   if(readXYZRaw((char*)&buf)) {
+       return 1;
+   }
+   if(_bitDepth==BIT_DEPTH_12) {
+     *x = twelveBitToSigned(&buf[0]);
+     *y = twelveBitToSigned(&buf[2]);
+     *z = twelveBitToSigned(&buf[4]);
+   } else {
+     *x = eightBitToSigned(&buf[0]);
+     *y = eightBitToSigned(&buf[1]);
+     *z = eightBitToSigned(&buf[2]);
+   }
+   
+   return 0;
+}
+ 
+int MMA8452::readXCount(int *x) {
+   char buf[2];
+   if(readXRaw((char*)&buf)) {
+       return 1;
+   }
+   if(_bitDepth==BIT_DEPTH_12) {
+     *x = twelveBitToSigned(&buf[0]);
+   } else {
+     *x = eightBitToSigned(&buf[0]);
+   }
+   return 0;
+}
+ 
+int MMA8452::readYCount(int *y) {
+   char buf[2];
+   if(readYRaw((char*)&buf)) {
+       return 1;
+   }
+   if(_bitDepth==BIT_DEPTH_12) {
+     *y = twelveBitToSigned(&buf[0]);
+   } else {
+     *y = eightBitToSigned(&buf[0]);
+   }
+   return 0;
+}
+ 
+int MMA8452::readZCount(int *z) {
+   char buf[2];
+   if(readZRaw((char*)&buf)) {
+       return 1;
+   }
+   if(_bitDepth==BIT_DEPTH_12) {
+     *z = twelveBitToSigned(&buf[0]);
+   } else {
+     *z = eightBitToSigned(&buf[0]);
+   }
+   return 0;
+}
+ 
+double MMA8452::convertCountToGravity(int count, int countsPerG) {
+   return (double)count/(double)countsPerG;
+}
+ 
+int MMA8452::getCountsPerG() {
+ // assume starting with DYNAMIC_RANGE_2G and BIT_DEPTH_12
+   int countsPerG = 1024;
+   if(_bitDepth==BIT_DEPTH_8) {
+      countsPerG = 64;
+   }
+   switch(_dynamicRange) {
+      case DYNAMIC_RANGE_4G:
+         countsPerG /= 2;
+      break;
+      case DYNAMIC_RANGE_8G:
+         countsPerG /= 4;
+      break;
+   }
+   return countsPerG;
+}
+ 
+int MMA8452::readXYZGravity(double *x, double *y, double *z) {
+   int xCount = 0, yCount = 0, zCount = 0;
+   if(readXYZCounts(&xCount,&yCount,&zCount)) {
+      return 1;
+   }
+   int countsPerG = getCountsPerG();
+   
+   *x = convertCountToGravity(xCount,countsPerG);
+   *y = convertCountToGravity(yCount,countsPerG);
+   *z = convertCountToGravity(zCount,countsPerG);
+   return 0;
+}
+ 
+int MMA8452::readXGravity(double *x) {
+   int xCount = 0;
+   if(readXCount(&xCount)) {
+      return 1;
+   }
+   int countsPerG = getCountsPerG();
+   
+   *x = convertCountToGravity(xCount,countsPerG);
+   return 0;
+}
+ 
+int MMA8452::readYGravity(double *y) {
+   int yCount = 0;
+   if(readYCount(&yCount)) {
+      return 1;
+   }
+   int countsPerG = getCountsPerG();
+   
+   *y = convertCountToGravity(yCount,countsPerG);
+   return 0;
+}
+ 
+int MMA8452::readZGravity(double *z) {
+   int zCount = 0;
+   if(readZCount(&zCount)) {
+      return 1;
+   }
+   int countsPerG = getCountsPerG();
+   
+   *z = convertCountToGravity(zCount,countsPerG);
+   return 0;
+}
+ 
+// apply an AND mask to a register. read register value, apply mask, write it back
+int MMA8452::logicalANDRegister(char addr, char mask) {
+   char value = 0;
+   // read register value
+   if(readRegister(addr,&value)) {
+      return 0;
+   }
+   // apply mask
+   value &= mask;
+   return writeRegister(addr,value);
+}
+ 
+ 
+// apply an OR mask to a register. read register value, apply mask, write it back
+int MMA8452::logicalORRegister(char addr, char mask) {
+   char value = 0;
+   // read register value
+   if(readRegister(addr,&value)) {
+      return 0;
+   }
+   // apply mask
+   value |= mask;
+   return writeRegister(addr,value);
+}
+ 
+// apply an OR mask to a register. read register value, apply mask, write it back
+int MMA8452::logicalXORRegister(char addr, char mask) {
+   char value = 0;
+   // read register value
+   if(readRegister(addr,&value)) {
+      return 0;
+   }
+   // apply mask
+   value ^= mask;
+   return writeRegister(addr,value);
+}
+ 
+// Write register (The device must be placed in Standby Mode to change the value of the registers) 
+int MMA8452::writeRegister(char addr, char data) {
+    // what this actually does is the following
+    // 1. tell I2C bus to start transaction
+    // 2. tell slave we want to write (slave address & write flag)
+    // 3. send the write address
+    // 4. send the data to write
+    // 5. tell I2C bus to end transaction
+ 
+    // we can wrap this up in the I2C library write function
+    char buf[2] = {0,0};
+    buf[0] = addr;
+    buf[1] = data;
+    return _i2c.write(MMA8452_ADDRESS, buf,2);
+    // note, could also do return writeRegister(addr,&data,1);
+}
+ 
+int MMA8452::eightBitToSigned(char *buf) {
+   return (int8_t)*buf;
+}
+ 
+int MMA8452::twelveBitToSigned(char *buf) {
+   // cheat by using the int16_t internal type
+   // all we need to do is convert to little-endian format and shift right
+   int16_t x = 0;
+   ((char*)&x)[1] = buf[0];
+   ((char*)&x)[0] = buf[1];
+   // note this only works because the below is an arithmetic right shift
+   return x>>4; 
+}
+ 
+int MMA8452::writeRegister(char addr, char *data, int nbytes) {
+    // writing multiple bytes is a little bit annoying because
+    // the I2C library doesn't support sending the address separately
+    // so we just do it manually
+    
+    // 1. tell I2C bus to start transaction
+    _i2c.start();
+    // 2. tell slave we want to write (slave address & write flag)
+    if(_i2c.write(_writeAddress)!=1) {
+       return 1;
+    }
+    // 3. send the write address
+    if(_i2c.write(addr)!=1) {
+       return 1;
+    }
+    // 4. send the data to write
+    for(int i=0; i<nbytes; i++) {
+       if(_i2c.write(data[i])!=1) {
+          return 1;
+       }
+    }
+    // 5. tell I2C bus to end transaction
+    _i2c.stop();
+    return 0;
+}
+ 
+int MMA8452::readRegister(char addr, char *dst, int nbytes) {
+    // this is a bit odd, but basically proceeds like this
+    // 1. Send a start command
+    // 2. Tell the slave we want to write (slave address & write flag)
+    // 3. Send the address of the register (addr)
+    // 4. Send another start command to delineate read portion
+    // 5. Tell the slave we want to read (slave address & read flag)
+    // 6. Read the register value bytes
+    // 7. Send a stop command
+    
+    // we can wrap this process in the I2C library read and write commands
+    if(_i2c.write(MMA8452_ADDRESS,&addr,1,true)) {
+       return 1;
+    }
+    return _i2c.read(MMA8452_ADDRESS,dst,nbytes);
+}
+ 
+// most registers are 1 byte, so here is a convenience function
+int MMA8452::readRegister(char addr, char *dst) {
+    return readRegister(addr,dst,1);
+}
+ 
+MMA8452::BitDepth MMA8452::getBitDepth() {
+   return _bitDepth;
+}
+ 
+#ifdef MMA8452_DEBUG
+void MMA8452::debugRegister(char reg) {
+   // get register value
+   char v = 0;
+   if(readRegister(reg,&v)) {
+      MMA8452_DBG("Error reading specified register");
+      return;
+   }
+   // print out details
+   switch(reg) {
+      case MMA8452_CTRL_REG_1:
+         MMA8452_DBG("CTRL_REG_1 has value: 0x%x",v);
+         MMA8452_DBG(" 7  ALSP_RATE_1: %d",(v&0x80)>>7);
+         MMA8452_DBG(" 6  ALSP_RATE_0: %d",(v&0x40)>>6);
+         MMA8452_DBG(" 5  DR2: %d",        (v&0x20)>>5);
+         MMA8452_DBG(" 4  DR1: %d",        (v&0x10)>>4);
+         MMA8452_DBG(" 3  DR0: %d",        (v&0x08)>>3);
+         MMA8452_DBG(" 2  LNOISE: %d",     (v&0x04)>>2);
+         MMA8452_DBG(" 1  FREAD: %d",      (v&0x02)>>1);
+         MMA8452_DBG(" 0  ACTIVE: %d",     (v&0x01));
+      break;
+        
+      case MMA8452_XYZ_DATA_CFG:
+         MMA8452_DBG("XYZ_DATA_CFG has value: 0x%x",v);
+         MMA8452_DBG(" 7  Unused: %d", (v&0x80)>>7);
+         MMA8452_DBG(" 6  0: %d",      (v&0x40)>>6);
+         MMA8452_DBG(" 5  0: %d",      (v&0x20)>>5);
+         MMA8452_DBG(" 4  HPF_Out: %d",(v&0x10)>>4);
+         MMA8452_DBG(" 3  0: %d",      (v&0x08)>>3);
+         MMA8452_DBG(" 2  0: %d",      (v&0x04)>>2);
+         MMA8452_DBG(" 1  FS1: %d",    (v&0x02)>>1);
+         MMA8452_DBG(" 0  FS0: %d",    (v&0x01));
+         switch(v&0x03) {
+            case 0:
+               MMA8452_DBG("Dynamic range: 2G");
+            break;
+            case 1:
+               MMA8452_DBG("Dynamic range: 4G");
+            break;
+            case 2:
+               MMA8452_DBG("Dynamic range: 8G");
+            break;
+            default:
+               MMA8452_DBG("Unknown dynamic range");
+            break;
+         }
+      break;
+      
+      case MMA8452_STATUS:
+         MMA8452_DBG("STATUS has value: 0x%x",v);
+         MMA8452_DBG(" 7  ZYXOW: %d",(v&0x80)>>7);
+         MMA8452_DBG(" 6  ZOW: %d",  (v&0x40)>>6);
+         MMA8452_DBG(" 5  YOW: %d",  (v&0x20)>>5);
+         MMA8452_DBG(" 4  XOW: %d",  (v&0x10)>>4);
+         MMA8452_DBG(" 3  ZYXDR: %d",(v&0x08)>>3);
+         MMA8452_DBG(" 2  ZDR: %d",  (v&0x04)>>2);
+         MMA8452_DBG(" 1  YDR: %d",  (v&0x02)>>1);
+         MMA8452_DBG(" 0  XDR: %d",  (v&0x01));
+      break;
+      
+      default:
+         MMA8452_DBG("Unknown register address: 0x%x",reg);
+      break;
+   }
+}
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MMA8452.h	Fri Oct 22 03:57:47 2021 +0000
@@ -0,0 +1,344 @@
+#pragma once
+ 
+// Authors: Ashley Mills, Nicholas Herriot
+/* Copyright (c) 2013 Vodafone, MIT License
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+ * and associated documentation files (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge, publish, distribute,
+ * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all copies or
+ * substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+ * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+ 
+// the SparkFun breakout board defaults to 1, set to 0 if SA0 jumper on the bottom of the board is set
+// see the Table 10. I2C Device Address Sequence in Freescale MMA8452Q pdf
+ 
+#include "mbed.h" 
+ 
+#define MMA8452_DEBUG 1
+ 
+// More info on MCU Master address can be found on section 5.10.1 of http://www.freescale.com/webapp/sps/site/prod_summary.jsp?code=MMA8452Q
+#define SA0 1
+#if SA0
+  #define MMA8452_ADDRESS 0x3A // 0x1D<<1  // SA0 is high, 0x1C if low - 
+#else
+  #define MMA8452_ADDRESS 0x38 // 0x1C<<1
+#endif
+ 
+// Register descriptions found in section 6 of pdf
+#define MMA8452_STATUS 0x00        // Type 'read' : Status of the data registers
+#define MMA8452_OUT_X_MSB 0x01     // Type 'read' : x axis - MSB of 2 byte sample
+#define MMA8452_OUT_X_LSB 0x02     // Type 'read' : x axis - LSB of 2 byte sample
+#define MMA8452_OUT_Y_MSB 0x03     // Type 'read' : y axis - MSB of 2 byte sample
+#define MMA8452_OUT_Y_LSB 0x04     // Type 'read' : y axis - LSB of 2 byte sample
+#define MMA8452_OUT_Z_MSB 0x05     // Type 'read' : z axis - MSB of 2 byte sample
+#define MMA8452_OUT_Z_LSB 0x06     // Type 'read' : z axis - LSB of 2 byte sample
+ 
+// register definitions
+#define MMA8452_XYZ_DATA_CFG 0x0E
+ 
+#define MMA8452_SYSMOD 0x0B        // Type 'read' : This tells you if device is active, sleep or standy 0x00=STANDBY 0x01=WAKE 0x02=SLEEP
+#define MMA8452_WHO_AM_I 0x0D      // Type 'read' : This should return the device id of 0x2A
+ 
+#define MMA8452_PL_STATUS 0x10     // Type 'read' : This shows portrait landscape mode orientation
+#define MMA8452_PL_CFG 0x11        // Type 'read/write' : This allows portrait landscape configuration
+#define MMA8452_PL_COUNT 0x12      // Type 'read' : This is the portraint landscape debounce counter
+#define MMA8452_PL_BF_ZCOMP 0x13   // Type 'read' :
+#define MMA8452_PL_THS_REG 0x14    // Type 'read' :
+ 
+#define MMA8452_FF_MT_CFG 0X15     // Type 'read/write' : Freefaul motion functional block configuration
+#define MMA8452_FF_MT_SRC 0X16     // Type 'read' : Freefaul motion event source register
+#define MMA8452_FF_MT_THS 0X17     // Type 'read' : Freefaul motion threshold register
+#define MMA8452_FF_COUNT 0X18      // Type 'read' : Freefaul motion debouce counter
+ 
+#define MMA8452_ASLP_COUNT 0x29    // Type 'read/write' : Counter settings for auto sleep
+#define MMA8452_CTRL_REG_1 0x2A    // Type 'read/write' :
+#define MMA8452_CTRL_REG_2 0x2B    // Type 'read/write' :
+#define MMA8452_CTRL_REG_3 0x2C    // Type 'read/write' :
+#define MMA8452_CTRL_REG_4 0x2D    // Type 'read/write' :
+#define MMA8452_CTRL_REG_5 0x2E    // Type 'read/write' :
+ 
+// Defined in table 13 of the Freescale PDF
+/// xxx these all need to have better names
+#define STANDBY 0x00                        // State value returned after a SYSMOD request, it can be in state STANDBY, WAKE or SLEEP
+#define WAKE 0x01                           // State value returned after a SYSMOD request, it can be in state STANDBY, WAKE or SLEEP
+#define SLEEP 0x02                          // State value returned after a SYSMOD request, it can be in state STANDBY, WAKE or SLEEP
+#define ACTIVE 0x01                         // Stage value returned and set in Control Register 1, it can be STANDBY=00, or ACTIVE=01
+ 
+#define TILT_STATUS 0x03        // Tilt Status (Read only)
+#define SRST_STATUS 0x04        // Sample Rate Status Register (Read only)
+#define SPCNT_STATUS 0x05       // Sleep Count Register (Read/Write)
+#define INTSU_STATUS 0x06       // Interrupt Setup Register
+#define MODE_STATUS 0x07        // Mode Register (Read/Write)
+#define SR_STATUS 0x08          // Auto-Wake and Active Mode Portrait/Landscape Samples per Seconds Register (Read/Write)
+#define PDET_STATUS 0x09        // Tap/Pulse Detection Register (Read/Write)
+#define PD_STATUS 0xA           // Tap/Pulse Debounce Count Register (Read/Write)
+ 
+// masks for enabling/disabling standby
+#define MMA8452_ACTIVE_MASK 0x01
+#define MMA8452_STANDBY_MASK 0xFE
+ 
+// mask for dynamic range reading and writing
+#define MMA8452_DYNAMIC_RANGE_MASK 0xFC
+ 
+// mask and shift for data rate reading and writing
+#define MMA8452_DATA_RATE_MASK 0xC7
+#define MMA8452_DATA_RATE_MASK_SHIFT 0x03
+ 
+// mask and shift for general reading and writing
+#define MMA8452_WRITE_MASK 0xFE
+#define MMA8452_READ_MASK 0x01
+ 
+// mask and shift for bit depth reading and writing
+#define MMA8452_BIT_DEPTH_MASK 0xFD
+#define MMA8452_BIT_DEPTH_MASK_SHIFT 0x01
+ 
+// status masks and shifts
+#define MMA8452_STATUS_ZYXDR_MASK 0x08
+#define MMA8452_STATUS_ZDR_MASK 0x04
+#define MMA8452_STATUS_YDR_MASK 0x02
+#define MMA8452_STATUS_XDR_MASK 0x01
+ 
+/**
+ * Wrapper for the MMA8452 I2C driven accelerometer.
+ */
+class MMA8452 {
+            
+    public:
+    
+       enum DynamicRange {
+           DYNAMIC_RANGE_2G=0x00,
+           DYNAMIC_RANGE_4G,
+           DYNAMIC_RANGE_8G,
+           DYNAMIC_RANGE_UNKNOWN
+       };
+        
+       enum BitDepth {
+           BIT_DEPTH_12=0x00,
+           BIT_DEPTH_8, // 1 sets fast read mode, hence the inversion
+           BIT_DEPTH_UNKNOWN
+       };
+       
+       enum DataRateHz {
+          RATE_800=0x00,
+          RATE_400,
+          RATE_200,
+          RATE_100,
+          RATE_50,
+          RATE_12_5,
+          RATE_6_25,
+          RATE_1_563,
+          RATE_UNKNOWN
+       };
+         
+       /**
+        * Create an accelerometer object connected to the specified I2C pins.
+        *
+        * @param sda I2C data port
+        * @param scl I2C clock port
+        * @param frequency 
+        * 
+        */ 
+      MMA8452(PinName sda, PinName scl, int frequency);
+       
+      /// Destructor
+      ~MMA8452();
+      
+      /**
+       * Puts the MMA8452 in active mode.
+       * @return 0 on success, 1 on failure.
+       */
+      int activate();
+ 
+      /**
+       * Puts the MMA8452 in standby.
+       * @return 0 on success, 1 on failure.
+       */
+      int standby();      
+    
+       /**
+        * Read the device ID from the accelerometer (should be 0x2a)
+        *
+        * @param dst pointer to store the ID
+        * @return 0 on success, 1 on failure.
+        */        
+      int getDeviceID(char* dst);  
+      
+      /**
+       * Read the MMA8452 status register.
+       *
+       * @param dst pointer to store the register value.
+       * @ return 0 on success, 1 on failure.
+       */
+      int getStatus(char* dst);  
+      
+      /** 
+       * Read the raw x, y, an z registers of the MMA8452 in one operation.
+       * All three registers are read sequentially and stored in the provided buffer.
+       * The stored values are signed 2's complement left-aligned 12 or 8 bit integers.
+       *
+       * @param dst The destination buffer. Note that this needs to be 3 bytes for
+       * BIT_DEPTH_8 and 6 bytes for BIT_DEPTH_12. It is upto the caller to ensure this.
+       * @return 0 for success, and 1 for failure
+       * @sa setBitDepth
+       */ 
+      int readXYZRaw(char *dst);
+      
+      /// Read the raw x register into the provided buffer. @sa readXYZRaw
+      int readXRaw(char *dst);
+      /// Read the raw y register into the provided buffer. @sa readXYZRaw
+      int readYRaw(char *dst);
+      /// Read the raw z register into the provided buffer. @sa readXYZRaw
+      int readZRaw(char *dst);
+      
+      /**
+       * Read the x, y, and z signed counts of the MMA8452 axes.
+       * 
+       * Count resolution is either 8 bits or 12 bits, and the range is either +-2G, +-4G, or +-8G
+       * depending on settings. The number of counts per G are 1024, 512, 256 for 2,4, and 8 G
+       * respectively at 12 bit resolution and 64, 32, 16 for 2, 4, and 8 G respectively at
+       * 8 bit resolution.
+       * 
+       * This function queries the MMA8452 and returns the signed counts for each axes.
+       *
+       * @param x Pointer to integer to store x count
+       * @param y Pointer to integer to store y count
+       * @param z Pointer to integer to store z count
+       * @return 0 on success, 1 on failure.
+       */
+      int readXYZCounts(int *x, int *y, int *z);
+      
+      /// Read the x axes signed count. @sa readXYZCounts
+      int readXCount(int *x);
+      /// Read the y axes signed count. @sa readXYZCounts
+      int readYCount(int *y);
+      /// Read the z axes signed count. @sa readXYZCounts
+      int readZCount(int *z);
+      
+      /**
+       * Read the x, y, and z accelerations measured in G.
+       *
+       * The measurement resolution is controlled via setBitDepth which can
+       * be 8 or 12, and by setDynamicRange, which can be +-2G, +-4G, or +-8G.
+       *
+       * @param x A pointer to the double to store the x acceleration in.
+       * @param y A pointer to the double to store the y acceleration in.
+       * @param z A pointer to the double to store the z acceleration in.
+       *
+       * @return 0 on success, 1 on failure.
+       */
+      int readXYZGravity(double *x, double *y, double *z);
+      
+      /// Read the x gravity in G into the provided double pointer. @sa readXYZGravity
+      int readXGravity(double *x);
+      /// Read the y gravity in G into the provided double pointer. @sa readXYZGravity
+      int readYGravity(double *y);
+      /// Read the z gravity in G into the provided double pointer. @sa readXYZGravity
+      int readZGravity(double *z);
+      
+      /// Returns 1 if data has been internally sampled (is available) for all axes since last read, 0 otherwise.
+      int isXYZReady();
+      /// Returns 1 if data has been internally sampled (is available) for the x-axis since last read, 0 otherwise.
+      int isXReady();
+      /// Returns 1 if data has been internally sampled (is available) for the y-axis since last read, 0 otherwise.
+      int isYReady();
+      /// Returns 1 if data has been internally sampled (is available) for the z-axis since last read, 0 otherwise.
+      int isZReady();
+            
+      /** 
+       * Reads a single byte from the specified MMA8452 register.
+       *
+       * @param addr The internal register address.
+       * @param dst The destination buffer address.
+       * @return 1 on success, 0 on failure.
+       */
+      int readRegister(char addr, char *dst);
+      
+      /** 
+       * Reads n bytes from the specified MMA8452 register.
+       *
+       * @param addr The internal register address.
+       * @param dst The destination buffer address.
+       * @param nbytes The number of bytes to read.
+       * @return 1 on success, 0 on failure.
+       */
+      int readRegister(char addr, char *dst, int nbytes);
+        
+       /** 
+        * Write to the specified MMA8452 register.
+        *
+        * @param addr The internal register address
+        * @param data Data byte to write
+        */    
+      int writeRegister(char addr, char data);
+      
+       /** 
+        * Write a data buffer to the specified MMA8452 register.
+        *
+        * @param addr The internal register address
+        * @param data Pointer to data buffer to write
+        * @param nbytes The length of the data buffer to write
+        */    
+      int writeRegister(char addr, char *data, int nbytes);
+      
+      int setDynamicRange(DynamicRange range, int toggleActivation=1);
+      int setBitDepth(BitDepth depth, int toggleActivation=1);
+      int setDataRate(DataRateHz dataRate, int toggleActivation=1);
+      
+      DynamicRange getDynamicRange();
+      DataRateHz getDataRate();
+      BitDepth getBitDepth();
+      
+      #ifdef MMA8452_DEBUG
+      void debugRegister(char reg);
+      #endif
+   
+    private:
+      /**
+       * Reads the specified register, applies the mask with logical AND, logical ORs the value
+       * and writes back the result to the register. If toggleActivation is set to true then the
+       * device is put in standby before the operation, and activated at the end.
+       * Setting it to false is useful for setting options on a device that you want to keep in
+       * standby.
+       */
+      int maskAndApplyRegister(char reg, char mask, char value, int toggleActivation);
+      
+      /// Reads the specified register, applies the mask with logical AND, and writes the result back.
+      int logicalANDRegister(char addr, char mask);
+      /// Reads the specified register, applies the mask with logical OR, and writes the result back.
+      int logicalORRegister(char addr, char mask);
+      /// Reads the specified register, applies the mask with logical XOR, and writes the result back.
+      int logicalXORRegister(char addr, char mask);
+      
+      /// Converts the 12-bit two's complement number in buf to a signed integer. Returns the integer.
+      int twelveBitToSigned(char *buf);
+      /// Converts the 8-bit two's complement number in buf to a signed integer. Returns the integer.
+      int eightBitToSigned(char *buf);
+      
+      /// Converts a count to a gravity using the supplied countsPerG. Returns the gravity.
+      double convertCountToGravity(int count, int countsPerG);
+      
+      /// Reads the register at addr, applies the mask with logical AND, and returns the result.
+      char getMaskedRegister(int addr, char mask);
+      
+      /// Get the counts per G for the current settings of bit depth and dynamic range.
+      int getCountsPerG();
+    
+      I2C _i2c;
+      int _frequency;
+      int _readAddress;
+      int _writeAddress;
+      
+      BitDepth _bitDepth;
+      DynamicRange _dynamicRange;       
+};
+            
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PinDetect.h	Fri Oct 22 03:57:47 2021 +0000
@@ -0,0 +1,501 @@
+/*
+    Copyright (c) 2010 Andy Kirkham
+ 
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+ 
+    The above copyright notice and this permission notice shall be included in
+    all copies or substantial portions of the Software.
+ 
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+    THE SOFTWARE.
+*/
+
+#ifndef AJK_PIN_DETECT_H
+#define AJK_PIN_DETECT_H
+
+#ifndef MBED_H
+#include "mbed.h"
+#endif
+
+#ifndef PINDETECT_PIN_ASSTERED
+#define PINDETECT_PIN_ASSTERED   1
+#endif
+
+#ifndef PINDETECT_SAMPLE_PERIOD
+#define PINDETECT_SAMPLE_PERIOD 20000
+#endif
+
+#ifndef PINDETECT_ASSERT_COUNT  
+#define PINDETECT_ASSERT_COUNT  1
+#endif
+
+#ifndef PINDETECT_HOLD_COUNT
+#define PINDETECT_HOLD_COUNT    50
+#endif
+
+namespace AjK {
+
+/** PinDetect adds mechanical switch debouncing to DigitialIn and interrupt callbacks.
+ *
+ * This is done by sampling the specified pin at regular intervals and detecting any
+ * change of state ( 0 -> 1 or 1 -> 0 ). When a state change is detected the attached
+ * callback handler is called. Additionally, if the pin stays in the same state after
+ * a state change for a defined period of time, an extra callback is made allowing a
+ * program to detect when a "key is pressed and held down" rather than a momentary
+ * key/switch press.
+ *
+ * All parameters are customisable which include:-
+ *  <ul>
+ *  <li> The sampling frequency. </li>
+ *  <li> The number of continuous samples until a state change is detected. </li> 
+ *  <li> The number of continuous samples until a key is assumed held after a state change. </li>
+ *  <li> The logic level which is assumed to be asserted (0volts or +volts). </li>
+ *  </ul>
+ *
+ * Only callbacks that have been attached will be called by the library.
+ *
+ * Example:
+ * @code
+ * #include "mbed.h"
+ * #include "PinDetect.h"
+ *
+ * PinDetect  pin( p30 );
+ * DigitialOut led1( LED1 );
+ * DigitialOut led2( LED2 );
+ * DigitialOut led3( LED3 );
+ * DigitialOut led4( LED4 );
+ *
+ * void keyPressed( void ) {
+ *     led2 = 1;
+ *     led3 = 0;
+ *     led4 = 0;
+ * }
+ *
+ * void keyReleased( void ) {
+ *     led2 = 0;
+ *     led3 = 0;
+ *     led4 = 0;
+ * }
+ *
+ * void keyPressedHeld( void ) {
+ *     led3 = 1;
+ * }
+ *
+ * void keyReleasedHeld( void ) {
+ *     led4 = 1;
+ * }
+ *
+ * int main() {
+ *
+ *     pin.mode( PullDown );
+ *     pin.attach_asserted( &keyPressed );
+ *     pin.attach_deasserted( &keyReleased );
+ *     pin.attach_asserted_held( &keyPressedHeld );
+ *     pin.attach_deasserted_held( &keyReleasedHeld );
+ *
+ *     // Sampling does not begin until you set a frequency.
+ *     // The default is 20ms. If you want a different frequency
+ *     // then pass the period in microseconds for example, for 10ms :-
+ *     //     pin.setSampleFrequency( 10000 );
+ *     //
+ *     pin.setSampleFrequency(); // Defaults to 20ms.
+ *
+ *     while( 1 ) {
+ *         led1 = !led1;
+ *         wait( 0.2 );
+ *     }
+ * }
+ * @endcode
+ *
+ * This example will flash led1 in a similar to a standard starting program.
+ *
+ * Applying a "1" (switch on) to pin 30 will switch on led2, removing the "1" to "0"
+ * (switch off) led2 goes out. Holding the "switch" at one for one second will switch
+ * on led3. An unasserted P30 (switched off) will, after one second illuminate led4
+ * when the deasserted calledback is called.
+ *
+ * The above is a very basic introduction. For more details:-
+ * @see example.h
+ */
+class PinDetect {
+
+protected:
+    DigitalIn   *_in;
+    Ticker      *_ticker;
+    int         _prevState;
+    int         _currentStateCounter;
+    int         _sampleTime;
+    int         _assertValue;
+    int         _samplesTillAssertReload;
+    int         _samplesTillAssert;
+    int         _samplesTillHeldReload;
+    int         _samplesTillHeld;
+    FunctionPointer _callbackAsserted;
+    FunctionPointer _callbackDeasserted;
+    FunctionPointer _callbackAssertedHeld;
+    FunctionPointer _callbackDeassertedHeld;
+    
+    /** initialise class
+     *
+     * @param PinName p is a valid pin that supports DigitalIn
+     * @param PinMode m The mode the DigitalIn should use.
+     */
+    void init(PinName p, PinMode m) {
+        _sampleTime              = PINDETECT_SAMPLE_PERIOD;
+        _samplesTillAssert       = PINDETECT_ASSERT_COUNT;
+        _samplesTillHeld         = 0;
+        _samplesTillAssertReload = PINDETECT_ASSERT_COUNT;
+        _samplesTillHeldReload   = PINDETECT_HOLD_COUNT;
+        _assertValue             = PINDETECT_PIN_ASSTERED;
+        
+        _in = new DigitalIn( p );
+        _in->mode( m );        
+        _prevState = _in->read();        
+        _ticker = new Ticker;
+    }
+    
+public:
+
+    friend class Ticker;
+    
+    PinDetect() { error("You must supply a PinName"); }
+
+    /** PinDetect constructor
+     *
+     * By default the PinMode is set to PullDown.
+     *
+     * @see http://mbed.org/handbook/DigitalIn
+     * @param p PinName is a valid pin that supports DigitalIn
+     */    
+    PinDetect(PinName p) {
+        init( p, PullDown );
+    }
+
+    /** PinDetect constructor
+     *
+     * @see http://mbed.org/handbook/DigitalIn
+     * @param PinName p is a valid pin that supports DigitalIn
+     * @param PinMode m The mode the DigitalIn should use.
+     */    
+    PinDetect(PinName p, PinMode m) {
+        init( p, m );
+    }
+    
+    /** PinDetect destructor
+     */    
+    ~PinDetect() {
+        if ( _ticker )  delete( _ticker );
+        if ( _in )      delete( _in );
+    }
+    
+    /** Set the sampling time in microseconds.
+     *
+     * @param int The time between pin samples in microseconds.
+     */
+    void setSampleFrequency(int i = PINDETECT_SAMPLE_PERIOD) { 
+        _sampleTime = i; 
+        _prevState  = _in->read();        
+        _ticker->attach_us( this, &PinDetect::isr, _sampleTime );
+    }
+    
+    /** Set the value used as assert.
+     *
+     * Defaults to 1 (ie if pin == 1 then pin asserted).
+     *
+     * @param int New assert value (1 or 0)
+     */
+    void setAssertValue (int i = PINDETECT_PIN_ASSTERED) { _assertValue = i & 1; }
+    
+    /** Set the number of continuous samples until assert assumed.
+     *
+     * Defaults to 1 (1 * sample frequency).
+     *
+     * @param int The number of continuous samples until assert assumed.
+     */    
+    void setSamplesTillAssert(int i) { _samplesTillAssertReload = i; }
+    
+    /** Set the number of continuous samples until held assumed.
+     *
+     * Defaults to 50 * sample frequency.
+     *
+     * @param int The number of continuous samples until held assumed.
+     */    
+    void setSamplesTillHeld(int i) { _samplesTillHeldReload = i; }
+    
+    /** Set the pin mode.
+     *
+     * @see http://mbed.org/projects/libraries/api/mbed/trunk/DigitalInOut#DigitalInOut.mode
+     * @param PinMode m The mode to pass on to the DigitalIn
+     */
+    void mode(PinMode m) { _in->mode( m ); }
+    
+    /** Attach a callback function 
+     *
+     * @code
+     *
+     * DigitalOut led1( LED1 );
+     * PinDetect pin( p30 );
+     *
+     * void myCallback( void ) {
+     *   led1 = 1;
+     * };
+     * 
+     * main() {
+     *     pin.attach_asserted( &myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is asserted.
+     * @param function A C function pointer
+     */
+    void attach_asserted(void (*function)(void)) {
+        _callbackAsserted.attach( function );
+    }
+    
+    /** Attach a callback object/method 
+     *
+     * @code
+     *
+     * class Bar {
+     *   public:
+     *     void myCallback( void ) { led1 = 1; }
+     * };
+     *
+     * DigitalOut led1( LED1 );
+     * PinDetect pin( p30 );
+     * Bar bar;
+     *
+     * main() {
+     *     pin.attach_asserted( &bar, &Bar::myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is asserted.
+     * @param object An object that conatins the callback method.
+     * @param method The method within the object to call.
+     */
+    template<typename T>
+    void attach_asserted(T *object, void (T::*member)(void)) {
+        _callbackAsserted.attach( object, member );        
+    }
+    
+    /** Attach a callback function 
+     *
+     * @code
+     *
+     * DigitalOut led1( LED1 );
+     * PinDetect pin( p30 );
+     *
+     * void myCallback( void ) {
+     *   led1 = 0;
+     * };
+     *
+     * main() {
+     *     pin.attach_deasserted( &myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is deasserted.
+     * @param function A C function pointer
+     */
+    void attach_deasserted(void (*function)(void)) {
+        _callbackDeasserted.attach( function );
+    }
+    
+    /** Attach a callback object/method
+     *
+     * @code
+     *
+     * class Bar {
+     *   public:
+     *     void myCallback( void ) { led1 = 0; }
+     * };
+     *
+     * DigitalOut led1( LED1 );
+     * PinDetect pin( p30 );
+     * Bar bar;
+     * 
+     * main() {
+     *     pin.attach_deasserted( &bar, &Bar::myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is deasserted.
+     * @param object An object that conatins the callback method.
+     * @param method The method within the object to call.
+     */
+    template<typename T>
+    void attach_deasserted(T *object, void (T::*member)(void)) {
+        _callbackDeasserted.attach( object, member );        
+    }
+    
+    /** Attach a callback function 
+     *
+     * @code
+     *
+     * DigitalOut led2( LED2 );
+     * PinDetect pin( p30 );
+     *
+     * void myCallback( void ) {
+     *   led2 = 1;
+     * };
+     *
+     * main() {
+     *     pin.attach_asserted_held( &myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is asserted and held.
+     * @param function A C function pointer
+     */
+    void attach_asserted_held(void (*function)(void)) {
+        _callbackAssertedHeld.attach( function );
+    }
+    
+    /** Attach a callback object/method
+     *
+     * @code
+     *
+     * class Bar {
+     *   public:
+     *     void myCallback( void ) { led2 = 0; }
+     * };
+     *
+     * DigitalOut led2( LED2 );
+     * PinDetect pin( p30 );
+     * Bar bar;
+     * 
+     * main() {
+     *     pin.attach_asserted_held( &bar, &Bar::myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is asserted and held.
+     * @param object An object that conatins the callback method.
+     * @param method The method within the object to call.
+     */
+    template<typename T>
+    void attach_asserted_held(T *object, void (T::*member)(void)) {
+        _callbackAssertedHeld.attach( object, member );        
+    }
+    
+    /** Attach a callback function 
+     *
+     * @code
+     *
+     * DigitalOut led3( LED3 );
+     * PinDetect pin( p30 );
+     *
+     * void myCallback( void ) {
+     *   led3 = 1;
+     * };
+     *
+     * main() {
+     *     pin.attach_deasserted_held( &myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is deasserted and held.
+     * @param function A C function pointer
+     */
+    void attach_deasserted_held(void (*function)(void)) {
+        _callbackDeassertedHeld.attach( function );
+    }
+    
+    /** Attach a callback object/method
+     *
+     * @code
+     *
+     * class Bar {
+     *   public:
+     *     void myCallback( void ) { led3 = 0; }
+     * };
+     *
+     * DigitalOut led3( LED3 );
+     * PinDetect pin( p30 );
+     * Bar bar;
+     * 
+     * main() {
+     *     pin.attach_deasserted_held( &bar, &Bar::myCallback );
+     * }
+     *
+     * @endcode
+     *
+     * Call this function when a pin is deasserted and held.
+     * @param object An object that conatins the callback method.
+     * @param method The method within the object to call.
+     */
+    template<typename T>
+    void attach_deasserted_held(T *object, void (T::*member)(void)) {
+        _callbackDeassertedHeld.attach( object, member );        
+    }
+    
+    /** operator int()
+     *
+     * Read the value of the pin being sampled.
+     */
+    operator int() { return _in->read(); }
+
+protected:    
+    /** The Ticker periodic callback function
+     */
+    void isr(void) {
+        int currentState = _in->read();
+    
+        if ( currentState != _prevState ) {
+            if ( _samplesTillAssert == 0 ) {
+                _prevState = currentState;
+                _samplesTillHeld = _samplesTillHeldReload;
+                if ( currentState == _assertValue ) 
+                    _callbackAsserted.call();
+                else                              
+                    _callbackDeasserted.call();
+            }
+            else {
+                _samplesTillAssert--;
+            }
+        }
+        else {
+            _samplesTillAssert = _samplesTillAssertReload;
+        }
+        
+        if ( _samplesTillHeld ) {
+            if ( _prevState == currentState ) {
+                _samplesTillHeld--;
+                if ( _samplesTillHeld == 0 ) {
+                    if ( currentState == _assertValue ) 
+                        _callbackAssertedHeld.call();
+                    else                              
+                        _callbackDeassertedHeld.call();
+                }
+            }
+            else {
+                _samplesTillHeld = 0;
+            }
+        }
+    }
+    
+};
+
+}; // namespace AjK ends.
+
+using namespace AjK;
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PinDetect.lib	Fri Oct 22 03:57:47 2021 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/AjK/code/PinDetect/#cb3afc45028b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Oct 22 03:57:47 2021 +0000
@@ -0,0 +1,100 @@
+/**
+
+Programmer: Andrew Shi
+Title: Lab 4 - Farkle Game
+Date: October 11 2021
+Description: Main function
+
+**/
+#include "Die.h"
+#include "FarkleGame.h"
+#include "PinDetect.h"
+
+#include "mbed.h"
+#include <time.h>
+
+using namespace std;
+
+Serial pc(USBTX,USBRX);
+
+PinDetect A(p21);
+PinDetect B(p22);
+PinDetect C(p23);
+
+int main(){
+    
+    //clear system
+    system("clear");
+    
+    //declare buttons
+    A.mode(PullUp);
+    B.mode(PullUp);
+    C.mode(PullUp); //unused
+    
+    //declare uLCD screen
+    uLCD_4DGL uLCD(p9,p10,p11);
+    uLCD.cls();
+    uLCD.display_control(PORTRAIT);
+    
+    //declare accelerometer
+    MMA8452 acc(p28, p27, 40000);
+    acc.setBitDepth(MMA8452::BIT_DEPTH_12);
+    acc.setDynamicRange(MMA8452::DYNAMIC_RANGE_4G);
+    acc.setDataRate(MMA8452::RATE_100);
+    
+    //declare dice number
+    int numDice = 6;
+    
+    //initialize FarkleGame object
+    FarkleGame game;
+    
+    game.scrnWipe(uLCD);
+    
+    //begin game
+    while(1){
+        //display intro and initialize values
+        game.dispIntro(uLCD, numDice);
+        game.init();
+        
+        //check for roll, adjust number of Dice
+        while(!game.checkRoll(acc)){   
+            if(!B){
+                numDice = (numDice+1)%7;
+                game.dispIntro(uLCD,numDice);
+            }        
+        }
+        
+        //roll dice when accelerometer is sensed, until A is clicked
+        while(A){
+            if(game.checkRoll(acc)){
+                //roll dice and displar
+                game.rollDice();
+                game.displayDice(uLCD, numDice);
+                
+                //update scores
+                game.loadVals(numDice);
+                game.updateScores();
+                
+                //display screens based on scores
+                if(game.calcScore() == 0){
+                    game.dispFarkle(uLCD);
+                    wait(3);
+                    break;
+                }
+                else{
+                    game.dispScore(uLCD);
+                }
+            }
+        }
+        
+        //display turn end screen
+        game.dispTurn(uLCD);
+        //wait for button to be pressed
+        while(A){
+        }
+        //reset numDice
+        numDice = 6;
+    }
+
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Fri Oct 22 03:57:47 2021 +0000
@@ -0,0 +1,1 @@
+https://os.mbed.com/users/mbed_official/code/mbed/builds/65be27845400
\ No newline at end of file