init
Dependencies: MPU6050 PinDetect circular_buffer
Revision 0:b416214256cd, committed 2017-11-07
- Comitter:
- OsmanKameric
- Date:
- Tue Nov 07 16:35:14 2017 +0000
- Commit message:
- FIRST
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.gitignore Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,4 @@ +.build +.mbed +projectfiles +*.py*
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CaseFSM/CaseFsm.cpp Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,63 @@ +#include <DeviceEmpty.h> +#include <DeviceFull.h> +#include <PhoneUndetected.h> +#include <PhoneDetected.h> +#include <CaseFsm.h> + +CaseFsmStates::CaseFsmStates() : deviceEmptyState_(new DeviceEmpty(*this,timer)), + deviceFullState_(new DeviceFull(*this,timer)), + phoneUndetectedState_(new PhoneUndetected(*this,timer)), + phoneDetectedState_(new PhoneDetected(*this,timer)) +{ + currentState(deviceEmptyState()); +} + + +CaseState* CaseFsmStates::deviceEmptyState() +{ + return deviceEmptyState_; +} + +void CaseFsm::timerCallback(){ + printf("Odoh u DEVICE EMPTY STATE\r\n"); + states_.currentState(states_.deviceEmptyState()); + } + +CaseState* CaseFsmStates::deviceFullState() +{ + return deviceFullState_; +} +CaseState* CaseFsmStates::phoneUndetectedState() +{ + return phoneUndetectedState_; +} +CaseState* CaseFsmStates::phoneDetectedState() +{ + return phoneDetectedState_; +} + +CaseState* CaseFsmStates::currentState() +{ + return currentState_; +} +void CaseFsmStates::currentState(CaseState* state) +{ + currentState_ = state; +} + +CaseFsmStates::~CaseFsmStates() +{ + delete deviceEmptyState_; + delete deviceFullState_; + delete phoneUndetectedState_; + delete phoneDetectedState_; +} + +CaseFsm::CaseFsm() : states_() +{ + + +} + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CaseFSM/CaseState.cpp Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,10 @@ +#include <CaseFsm.h> +#include <CaseState.h> + +CaseState::CaseState(CaseFsmStates& states,Timer& timer): states_(states),stateTimer_(timer){} + +CaseState* CaseState::handle(SwitchPosition& event) { return states_.currentState(); } +CaseState* CaseState::handle(RFIDEvent& event) { return states_.currentState(); } +CaseState* CaseState::handle(TimerEnd& event) { return states_.currentState(); } + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CaseFSM/DeviceEmpty.cpp Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,18 @@ +#include <DeviceEmpty.h> +#include <CaseEvents.h> +#include <CaseFsm.h> + +DeviceEmpty::DeviceEmpty(CaseFsmStates& states, Timer& timer): CaseState(states, timer) +{ + + +} + +CaseState* DeviceEmpty::handle(SwitchPosition& event) +{ + printf("Odoh u DEVICE FULL STATE\r\n"); + + return states_.deviceFullState(); +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CaseFSM/DeviceFull.cpp Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,40 @@ +#include <DeviceEmpty.h> +#include <DeviceFull.h> +#include <CaseFsm.h> + + + +DeviceFull::DeviceFull(CaseFsmStates& states, Timer& timer) : CaseState(states,timer) +{ +} + +CaseState* DeviceFull::handle(SwitchPosition& event) +{ + printf("Odoh u DEVICE EMPTY STATE\r\n"); + return states_.deviceEmptyState(); +} + + + +CaseState* DeviceFull::handle(RFIDEvent& event) +{ + //printf("%d\r\n",event.cardType); + //for(int i=0;i<event.size;i++){ + // printf(" %X",event.uid[i]); + // } + //printf("\r\n"); + if(5!=5) { + printf("Odoh u PHONE UNDETECTED STATE\r\n"); + return states_.phoneUndetectedState(); + } else { + printf("Odoh u PHONE DETECTED STATE\r\n"); + return states_.phoneDetectedState(); + } +} +CaseState* DeviceFull::handle(TimerEnd& event) +{ + printf("Odoh u DEVICE UNDETECTED STATE\r\n"); + return states_.phoneUndetectedState(); +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CaseFSM/PhoneDetected.cpp Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,20 @@ +#include <PhoneDetected.h> +#include <DeviceEmpty.h> +#include <CaseEvents.h> +#include <CaseFsm.h> + +PhoneDetected::PhoneDetected(CaseFsmStates& states, Timer& timer): CaseState(states,timer) +{ + + +} + +CaseState* PhoneDetected::handle(SwitchPosition& event) +{ + + printf("Odoh u DEVICE EMPTY STATE\r\n"); + return states_.deviceEmptyState(); +} + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CaseFSM/PhoneUndetected.cpp Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,16 @@ +#include <PhoneUndetected.h> +#include <DeviceEmpty.h> +#include <CaseEvents.h> +#include <CaseFsm.h> + +PhoneUndetected::PhoneUndetected(CaseFsmStates& states, Timer& timer): CaseState(states,timer) {} + +CaseState* PhoneUndetected::handle(SwitchPosition& event) +{ + + printf("Odoh u DEVICE EMPTY STATE\r\n"); + return states_.deviceEmptyState(); +} + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CaseFSM/include/CaseEvents.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,12 @@ +#ifndef CASEFSM_EVENTS_H_ +#define CASEFSM_EVENTS_H_ + +struct SwitchPosition {}; +struct RFIDEvent { + uint8_t cardType; + uint8_t uid[10]; + uint8_t size; + }; +struct TimerEnd {}; + +#endif /* ifndef CASEFSM_EVENTS_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CaseFSM/include/CaseFsm.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,66 @@ +#ifndef CASEFSM_FSM_H_ +#define CASEFSM_FSM_H_ +#include <CaseState.h> +#include "mbed.h" + +#include <CaseEvents.h> + +struct SwitchPosition; +struct RFIDEvent; + +class CaseFsmStates +{ +public: + CaseFsmStates(); + + CaseState* deviceEmptyState(); + CaseState* deviceFullState(); + CaseState* phoneUndetectedState(); + CaseState* phoneDetectedState(); + CaseState* currentState(); + + void currentState(CaseState* state); + ~CaseFsmStates(); + +private: + + CaseState* deviceEmptyState_; + CaseState* deviceFullState_; + CaseState* phoneUndetectedState_; + CaseState* phoneDetectedState_; + CaseState* currentState_; + + Timer timer; + +}; + +class CaseFsm +{ +public: + CaseFsm(); + Timeout rfidTimeout; + void timerCallback(); + template <typename Event> + void handle(Event& event) { + CaseState* state = states_.currentState()->handle(event); + if(state==states_.deviceFullState()) { + rfidTimeout.attach(this, &CaseFsm::timerCallback, 5.0); + } + if(state==states_.deviceEmptyState()) { + rfidTimeout.detach(); + } + if(state==states_.phoneDetectedState()) { + rfidTimeout.detach(); + } + states_.currentState(state); + } + bool DeviceInFullState(){ + return states_.currentState() == states_.deviceFullState(); + }; + virtual ~CaseFsm() {} + +private: + CaseFsmStates states_; + +}; +#endif /* ifndef CASEFSM_FSM_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CaseFSM/include/CaseState.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,21 @@ +#ifndef CASEFSM_STATE_H_ +#define CASEFSM_STATE_H_ +#include "mbed.h" +struct SwitchPosition; +struct RFIDEvent; +struct TimerEnd; +class CaseFsmStates; + +class CaseState { + public: + CaseState(CaseFsmStates& state, Timer& timer); + virtual CaseState* handle(SwitchPosition& event); + virtual CaseState* handle(RFIDEvent& event); + virtual CaseState* handle(TimerEnd& event); + virtual ~CaseState() {} + + protected: + CaseFsmStates& states_; + Timer& stateTimer_; +}; +#endif /* ifndef CASEFSM_STATE_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CaseFSM/include/DeviceEmpty.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,14 @@ +#ifndef CASEFSM_DEVICEEMPTY_H_ +#define CASEFSM_DEVICEEMPTY_H_ + +#include <CaseState.h> +#include "mbed.h" + +class CaseFsmStates; + +class DeviceEmpty : public CaseState { + public: + DeviceEmpty(CaseFsmStates& states, Timer& timer); + CaseState* handle(SwitchPosition& event); +}; +#endif /* ifndef CASEFSM_DEVICEEMPTY_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CaseFSM/include/DeviceFull.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,18 @@ +#ifndef CASEFSM_DEVICEFULL_H_ +#define CASEFSM_DEVICEFULL_H_ + +#include <CaseState.h> + +class CaseFsmStates; + +class DeviceFull : public CaseState +{ +public: + DeviceFull(CaseFsmStates& states, Timer& timer); + CaseState* handle(SwitchPosition& event); + CaseState* handle(RFIDEvent& event); + CaseState* handle(TimerEnd& event); + + +}; +#endif /* ifndef CASEFSM_DEVICEFULL_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CaseFSM/include/PhoneDetected.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,17 @@ +#ifndef CASEFSM_PHONEDETECTED_H_ +#define CASEFSM_PHONEDETECTED_H_ + +#include <CaseState.h> + +class CaseFsmStates; + +class PhoneDetected : public CaseState { + public: + PhoneDetected(CaseFsmStates& states, Timer& timer); + CaseState* handle(SwitchPosition& event); + + private: + unsigned timeForLongPress_; +}; + +#endif /* ifndef CASEFSM_PHONEDETECTED_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/CaseFSM/include/PhoneUndetected.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,18 @@ +#ifndef CASEFSM_PHONEUNDETECTED_H_ +#define CASEFSM_PHONEUNDETECTED_H_ + +#include <CaseState.h> + +class CaseFsmStates; + +class PhoneUndetected : public CaseState { + public: + PhoneUndetected(CaseFsmStates& states, Timer& timer); + CaseState* handle(SwitchPosition& event); + + private: + unsigned timeForLongPress_; + +}; + +#endif /* ifndef CASEFSM_PHONEUNDETECTED_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DataLogger/DataLogger.cpp Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,155 @@ + +#include <stdio.h> + + +#include "log.h" +#include "DataLogger.h" + +using namespace std; + + + +template<class T> +void DataLogger<T>::savelog(T templog) +{ + Log nule(0,0,0,0); + uint16_t del=position(); + + if (_index < (DATASIZE - 1)) { + _index++; + _datalist[_index] = templog; + + } + else { + _index = DATASIZE-del; + + for (int k = 0; k<(DATASIZE-del) && _index!=-1; k++) + _datalist[k]=_datalist[del+k]; + + for (int k = 0; k<DATASIZE; k++){ + if(k>=(DATASIZE-del)) + _datalist[k]=nule; + } + + _datalist[DATASIZE-del]=templog; + +} + + } + +template<class T> +void DataLogger<T>::print() +{ + //Log *p; + //p=getfirst(); + //cout<<"dirst"<<(*p).getTime()<<endl; + + printf("\nPrint\n"); + for (int i = 0; i < DATASIZE; i++) { + printf("Date %d ", _datalist[i].getDate()); + printf("Time %d ", _datalist[i].getTime()); + printf("Fsm %d ", _datalist[i].getFsmtype()); + printf("Event %d\n", _datalist[i].getEvent()); + + } +} + +template<class T> +uint8_t DataLogger<T>::position() +{ + int k=0; + int datum=_datalist[0].getDate(); + for (int i = 0; i < DATASIZE; i++) { + if(_datalist[i].getDate()==datum) + k++; + } + return k; +} + + + + +template<class T> +uint16_t DataLogger<T>::getsize() +{ + + return sizeof(_datalist) / 4; +} + +template<class T> +T* DataLogger<T>::getfirst(){ + + return _datalist; + +} + +template<class T> +T* DataLogger<T>::getlast(){ +int i=0; + for(i;i<DATASIZE;i++){ + if(_datalist[i].getDate()==0) + break; + + } + return (_datalist+i-1); +} + +template<class T> +uint16_t DataLogger<T>::getnumberOfDays(){ + uint16_t countDays=1; + Log *p1=getfirst(); + Log *p2; + p2=getLastStop(); + uint16_t currentDate=(*p1).getDate(); + + if((*p2).getDate()==currentDate && (*p2).getDate()!=0) + countDays; + + // cout<<"last stop "<<(*p1).getTime()<<endl; + + + while(p1!=p2){ + // cout<<"d "<<(*p1).getDate()<<endl; + if((*p1).getDate() != currentDate){ + countDays++; + currentDate=(*p1).getDate(); + } + p1++; + } + + // for(int i=0;i<DATASIZE;i++){ + // if(_datalist[i].getDate() != _datalist[i+1].getDate()) + // countDays++; + + // } + // cout<<"dani "<<countDays<<endl; + + return countDays; +} + + +template<class T> +T* DataLogger<T>::getLastStop(){ + + //cout<<"getlaststop"<<endl; + + int i=DATASIZE-1; + + for(i; i>=0; i--) + if (_datalist[i].getDate()!=0 && _datalist[i].getEvent()==0) + { + //cout<<"i "<<i<<" "<<_datalist[i].getTime()<<"Event "<<_datalist[i].getEvent()<<endl; + break; + + } + + return (_datalist+i); +} + + + + + +template class DataLogger<Log>; + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DataLogger/DataLogger.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,44 @@ +#ifndef _DATALOGGER_H +#define _DATALOGGER_H + +//#include "DataLogger.h" +#include <stdint.h> + +#define DATASIZE 20 + +using namespace std; + + +//*************************************************************LOGGER**************************************************************************// + +template<class T> +class DataLogger{ +private: + + T _datalist[DATASIZE]; + int _index; + + +public: + + + DataLogger(){//cout<<"Default Constructor"<<endl; + for(int i=0;i<DATASIZE;i++) + _datalist[i]._date=0; + _index=-1;} + DataLogger(T b){//cout<<"Constructor"<<endl; + _index=-1;} + void savelog(T templog); + void print(); + uint16_t getsize(); + uint8_t position(); + T* getfirst(); + T* getlast(); + uint16_t getnumberOfDays(); + T* getLastStop(); + + + +}; +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Log/log.cpp Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,83 @@ + #include <iostream> + #include <stdio.h> + #include <stdlib.h> + #include <stdint.h> + #include <bitset> + +// #include <string> +// #include <typeinfo> + +#include "log.h" + +Log::Log(uint16_t ttime, uint8_t fsmtype, uint8_t event,uint16_t date) +{ + uint16_t h=ttime/100; + uint16_t m=ttime%100; + uint16_t data=fsmtype<<12|event<<11; + h=h<<6; + _date=date; + _data=data|h|m; +} + +Log::Log(){_data=0;} + +uint16_t Log::getsize() +{ + return sizeof(_data); +} +uint16_t Log::getDate() const +{ + return _date; +} + +bool Log::getFsmtype() const +{ + return (_data & (1 << 12))!=0; +} + +bool Log::getEvent() const +{ + return (_data & (1 << 11))!=0; +} + +uint16_t Log::getTime() const +{ +char temp[5]; +//string z; +uint16_t x = (_data & 0x7c0)>>6; +uint16_t y = (_data & 0x3F); +//cout<<x<<" "<<y<<endl; +if(y<=9) + sprintf(temp, "%d0%d", x,y); + //z=to_string(x)+"0"+to_string(y); +else + sprintf(temp, "%d%d", x,y); + //z =to_string(x)+to_string(y); + temp[5]='\0'; + //std::string z(temp); + //cout<<"temp "<<temp<<endl; +return atoi(temp); +} + +Log& Log::operator =(const Log &a){ // b.operator=(a); + + uint16_t date=a.getDate(); + _date=date; + uint16_t h=a.getTime()/100; + uint16_t m=a.getTime()%100; + uint16_t data=((a.getFsmtype())<<12)|((a.getEvent())<<11); + h=h<<6; + _data=data|h|m; + return *this; +} + +void Log::setLog(uint16_t ttime, uint8_t fsmtype, uint8_t event,uint16_t date) +{ + uint16_t h=ttime/100; + uint16_t m=ttime%100; + uint16_t data=fsmtype<<12|event<<11; + h=h<<6; + _data=data|h|m; + _date=date; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Log/log.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,30 @@ +#ifndef _LOG_H +#define _LOG_H + +#include <stdint.h> +//#include <stdio.h> +//#include <stdlib.h> + + +//************************************************************LOG*******************************************************************// +class Log{ +private: + +public: +uint16_t _data; +uint16_t _date; +Log(uint16_t ttime, uint8_t fsmtype, uint8_t event, uint16_t date); +Log(); +uint16_t getsize(); +bool getFsmtype() const; +bool getEvent() const; +uint16_t getTime() const; +uint16_t getDate() const; +void setLog(uint16_t ttime, uint8_t fsmtype, uint8_t event,uint16_t date); + +Log& operator =(const Log &a); + +}; + +#endif +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MFRC522.cpp Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,1154 @@ +/* +* MFRC522.cpp - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. +* _Please_ see the comments in MFRC522.h - they give useful hints and background. +* Released into the public domain. +*/ + +#include "MFRC522.h" + +static const char* const _TypeNamePICC[] = +{ + "Unknown type", + "PICC compliant with ISO/IEC 14443-4", + "PICC compliant with ISO/IEC 18092 (NFC)", + "MIFARE Mini, 320 bytes", + "MIFARE 1KB", + "MIFARE 4KB", + "MIFARE Ultralight or Ultralight C", + "MIFARE Plus", + "MIFARE TNP3XXX", + + /* not complete UID */ + "SAK indicates UID is not complete" +}; + +static const char* const _ErrorMessage[] = +{ + "Unknown error", + "Success", + "Error in communication", + "Collision detected", + "Timeout in communication", + "A buffer is not big enough", + "Internal error in the code, should not happen", + "Invalid argument", + "The CRC_A does not match", + "A MIFARE PICC responded with NAK" +}; + +#define MFRC522_MaxPICCs (sizeof(_TypeNamePICC)/sizeof(_TypeNamePICC[0])) +#define MFRC522_MaxError (sizeof(_ErrorMessage)/sizeof(_ErrorMessage[0])) + +///////////////////////////////////////////////////////////////////////////////////// +// Functions for setting up the driver +///////////////////////////////////////////////////////////////////////////////////// + +/** + * Constructor. + * Prepares the output pins. + */ +MFRC522::MFRC522(PinName mosi, + PinName miso, + PinName sclk, + PinName cs, + PinName reset) : m_SPI(mosi, miso, sclk), m_CS(cs), m_RESET(reset) +{ + /* Configure SPI bus */ + m_SPI.format(8, 0); + m_SPI.frequency(8000000); + + /* Release SPI-CS pin */ + m_CS = 1; + + /* Release RESET pin */ + m_RESET = 1; +} // End constructor + + +/** + * Destructor. + */ +MFRC522::~MFRC522() +{ + +} + + +///////////////////////////////////////////////////////////////////////////////////// +// Basic interface functions for communicating with the MFRC522 +///////////////////////////////////////////////////////////////////////////////////// + +/** + * Writes a byte to the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.2. + */ +void MFRC522::PCD_WriteRegister(uint8_t reg, uint8_t value) +{ + m_CS = 0; /* Select SPI Chip MFRC522 */ + + // MSB == 0 is for writing. LSB is not used in address. Datasheet section 8.1.2.3. + (void) m_SPI.write(reg & 0x7E); + (void) m_SPI.write(value); + + m_CS = 1; /* Release SPI Chip MFRC522 */ +} // End PCD_WriteRegister() + +/** + * Writes a number of bytes to the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.2. + */ +void MFRC522::PCD_WriteRegister(uint8_t reg, uint8_t count, uint8_t *values) +{ + m_CS = 0; /* Select SPI Chip MFRC522 */ + + // MSB == 0 is for writing. LSB is not used in address. Datasheet section 8.1.2.3. + (void) m_SPI.write(reg & 0x7E); + for (uint8_t index = 0; index < count; index++) + { + (void) m_SPI.write(values[index]); + } + + m_CS = 1; /* Release SPI Chip MFRC522 */ +} // End PCD_WriteRegister() + +/** + * Reads a byte from the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.2. + */ +uint8_t MFRC522::PCD_ReadRegister(uint8_t reg) +{ + uint8_t value; + m_CS = 0; /* Select SPI Chip MFRC522 */ + + // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3. + (void) m_SPI.write(0x80 | reg); + + // Read the value back. Send 0 to stop reading. + value = m_SPI.write(0); + + m_CS = 1; /* Release SPI Chip MFRC522 */ + + return value; +} // End PCD_ReadRegister() + +/** + * Reads a number of bytes from the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.2. + */ +void MFRC522::PCD_ReadRegister(uint8_t reg, uint8_t count, uint8_t *values, uint8_t rxAlign) +{ + if (count == 0) { return; } + + uint8_t address = 0x80 | reg; // MSB == 1 is for reading. LSB is not used in address. Datasheet section 8.1.2.3. + uint8_t index = 0; // Index in values array. + + m_CS = 0; /* Select SPI Chip MFRC522 */ + count--; // One read is performed outside of the loop + (void) m_SPI.write(address); // Tell MFRC522 which address we want to read + + while (index < count) + { + if ((index == 0) && rxAlign) // Only update bit positions rxAlign..7 in values[0] + { + // Create bit mask for bit positions rxAlign..7 + uint8_t mask = 0; + for (uint8_t i = rxAlign; i <= 7; i++) + { + mask |= (1 << i); + } + + // Read value and tell that we want to read the same address again. + uint8_t value = m_SPI.write(address); + + // Apply mask to both current value of values[0] and the new data in value. + values[0] = (values[index] & ~mask) | (value & mask); + } + else + { + // Read value and tell that we want to read the same address again. + values[index] = m_SPI.write(address); + } + + index++; + } + + values[index] = m_SPI.write(0); // Read the final byte. Send 0 to stop reading. + + m_CS = 1; /* Release SPI Chip MFRC522 */ +} // End PCD_ReadRegister() + +/** + * Sets the bits given in mask in register reg. + */ +void MFRC522::PCD_SetRegisterBits(uint8_t reg, uint8_t mask) +{ + uint8_t tmp = PCD_ReadRegister(reg); + PCD_WriteRegister(reg, tmp | mask); // set bit mask +} // End PCD_SetRegisterBitMask() + +/** + * Clears the bits given in mask from register reg. + */ +void MFRC522::PCD_ClrRegisterBits(uint8_t reg, uint8_t mask) +{ + uint8_t tmp = PCD_ReadRegister(reg); + PCD_WriteRegister(reg, tmp & (~mask)); // clear bit mask +} // End PCD_ClearRegisterBitMask() + + +/** + * Use the CRC coprocessor in the MFRC522 to calculate a CRC_A. + */ +uint8_t MFRC522::PCD_CalculateCRC(uint8_t *data, uint8_t length, uint8_t *result) +{ + PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command. + PCD_WriteRegister(DivIrqReg, 0x04); // Clear the CRCIRq interrupt request bit + PCD_SetRegisterBits(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization + PCD_WriteRegister(FIFODataReg, length, data); // Write data to the FIFO + PCD_WriteRegister(CommandReg, PCD_CalcCRC); // Start the calculation + + // Wait for the CRC calculation to complete. Each iteration of the while-loop takes 17.73us. + uint16_t i = 5000; + uint8_t n; + while (1) + { + n = PCD_ReadRegister(DivIrqReg); // DivIrqReg[7..0] bits are: Set2 reserved reserved MfinActIRq reserved CRCIRq reserved reserved + if (n & 0x04) + { + // CRCIRq bit set - calculation done + break; + } + + if (--i == 0) + { + // The emergency break. We will eventually terminate on this one after 89ms. + // Communication with the MFRC522 might be down. + return STATUS_TIMEOUT; + } + } + + // Stop calculating CRC for new content in the FIFO. + PCD_WriteRegister(CommandReg, PCD_Idle); + + // Transfer the result from the registers to the result buffer + result[0] = PCD_ReadRegister(CRCResultRegL); + result[1] = PCD_ReadRegister(CRCResultRegH); + return STATUS_OK; +} // End PCD_CalculateCRC() + + +///////////////////////////////////////////////////////////////////////////////////// +// Functions for manipulating the MFRC522 +///////////////////////////////////////////////////////////////////////////////////// + +/** + * Initializes the MFRC522 chip. + */ +void MFRC522::PCD_Init() +{ + /* Reset MFRC522 */ + m_RESET = 0; + wait_ms(10); + m_RESET = 1; + + // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74us. Let us be generous: 50ms. + wait_ms(50); + + // When communicating with a PICC we need a timeout if something goes wrong. + // f_timer = 13.56 MHz / (2*TPreScaler+1) where TPreScaler = [TPrescaler_Hi:TPrescaler_Lo]. + // TPrescaler_Hi are the four low bits in TModeReg. TPrescaler_Lo is TPrescalerReg. + PCD_WriteRegister(TModeReg, 0x80); // TAuto=1; timer starts automatically at the end of the transmission in all communication modes at all speeds + PCD_WriteRegister(TPrescalerReg, 0xA9); // TPreScaler = TModeReg[3..0]:TPrescalerReg, ie 0x0A9 = 169 => f_timer=40kHz, ie a timer period of 25us. + PCD_WriteRegister(TReloadRegH, 0x03); // Reload timer with 0x3E8 = 1000, ie 25ms before timeout. + PCD_WriteRegister(TReloadRegL, 0xE8); + + PCD_WriteRegister(TxASKReg, 0x40); // Default 0x00. Force a 100 % ASK modulation independent of the ModGsPReg register setting + PCD_WriteRegister(ModeReg, 0x3D); // Default 0x3F. Set the preset value for the CRC coprocessor for the CalcCRC command to 0x6363 (ISO 14443-3 part 6.2.4) + + PCD_WriteRegister(RFCfgReg, (0x07<<4)); // Set Rx Gain to max + + PCD_AntennaOn(); // Enable the antenna driver pins TX1 and TX2 (they were disabled by the reset) +} // End PCD_Init() + +/** + * Performs a soft reset on the MFRC522 chip and waits for it to be ready again. + */ +void MFRC522::PCD_Reset() +{ + PCD_WriteRegister(CommandReg, PCD_SoftReset); // Issue the SoftReset command. + // The datasheet does not mention how long the SoftRest command takes to complete. + // But the MFRC522 might have been in soft power-down mode (triggered by bit 4 of CommandReg) + // Section 8.8.2 in the datasheet says the oscillator start-up time is the start up time of the crystal + 37,74us. Let us be generous: 50ms. + wait_ms(50); + + // Wait for the PowerDown bit in CommandReg to be cleared + while (PCD_ReadRegister(CommandReg) & (1<<4)) + { + // PCD still restarting - unlikely after waiting 50ms, but better safe than sorry. + } +} // End PCD_Reset() + +/** + * Turns the antenna on by enabling pins TX1 and TX2. + * After a reset these pins disabled. + */ +void MFRC522::PCD_AntennaOn() +{ + uint8_t value = PCD_ReadRegister(TxControlReg); + if ((value & 0x03) != 0x03) + { + PCD_WriteRegister(TxControlReg, value | 0x03); + } +} // End PCD_AntennaOn() + +///////////////////////////////////////////////////////////////////////////////////// +// Functions for communicating with PICCs +///////////////////////////////////////////////////////////////////////////////////// + +/** + * Executes the Transceive command. + * CRC validation can only be done if backData and backLen are specified. + */ +uint8_t MFRC522::PCD_TransceiveData(uint8_t *sendData, + uint8_t sendLen, + uint8_t *backData, + uint8_t *backLen, + uint8_t *validBits, + uint8_t rxAlign, + bool checkCRC) +{ + uint8_t waitIRq = 0x30; // RxIRq and IdleIRq + return PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, sendData, sendLen, backData, backLen, validBits, rxAlign, checkCRC); +} // End PCD_TransceiveData() + +/** + * Transfers data to the MFRC522 FIFO, executes a commend, waits for completion and transfers data back from the FIFO. + * CRC validation can only be done if backData and backLen are specified. + */ +uint8_t MFRC522::PCD_CommunicateWithPICC(uint8_t command, + uint8_t waitIRq, + uint8_t *sendData, + uint8_t sendLen, + uint8_t *backData, + uint8_t *backLen, + uint8_t *validBits, + uint8_t rxAlign, + bool checkCRC) +{ + uint8_t n, _validBits = 0; + uint32_t i; + + // Prepare values for BitFramingReg + uint8_t txLastBits = validBits ? *validBits : 0; + uint8_t bitFraming = (rxAlign << 4) + txLastBits; // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] + + PCD_WriteRegister(CommandReg, PCD_Idle); // Stop any active command. + PCD_WriteRegister(ComIrqReg, 0x7F); // Clear all seven interrupt request bits + PCD_SetRegisterBits(FIFOLevelReg, 0x80); // FlushBuffer = 1, FIFO initialization + PCD_WriteRegister(FIFODataReg, sendLen, sendData); // Write sendData to the FIFO + PCD_WriteRegister(BitFramingReg, bitFraming); // Bit adjustments + PCD_WriteRegister(CommandReg, command); // Execute the command + if (command == PCD_Transceive) + { + PCD_SetRegisterBits(BitFramingReg, 0x80); // StartSend=1, transmission of data starts + } + + // Wait for the command to complete. + // In PCD_Init() we set the TAuto flag in TModeReg. This means the timer automatically starts when the PCD stops transmitting. + // Each iteration of the do-while-loop takes 17.86us. + i = 2000; + while (1) + { + n = PCD_ReadRegister(ComIrqReg); // ComIrqReg[7..0] bits are: Set1 TxIRq RxIRq IdleIRq HiAlertIRq LoAlertIRq ErrIRq TimerIRq + if (n & waitIRq) + { // One of the interrupts that signal success has been set. + break; + } + + if (n & 0x01) + { // Timer interrupt - nothing received in 25ms + return STATUS_TIMEOUT; + } + + if (--i == 0) + { // The emergency break. If all other condions fail we will eventually terminate on this one after 35.7ms. Communication with the MFRC522 might be down. + return STATUS_TIMEOUT; + } + } + + // Stop now if any errors except collisions were detected. + uint8_t errorRegValue = PCD_ReadRegister(ErrorReg); // ErrorReg[7..0] bits are: WrErr TempErr reserved BufferOvfl CollErr CRCErr ParityErr ProtocolErr + if (errorRegValue & 0x13) + { // BufferOvfl ParityErr ProtocolErr + return STATUS_ERROR; + } + + // If the caller wants data back, get it from the MFRC522. + if (backData && backLen) + { + n = PCD_ReadRegister(FIFOLevelReg); // Number of bytes in the FIFO + if (n > *backLen) + { + return STATUS_NO_ROOM; + } + + *backLen = n; // Number of bytes returned + PCD_ReadRegister(FIFODataReg, n, backData, rxAlign); // Get received data from FIFO + _validBits = PCD_ReadRegister(ControlReg) & 0x07; // RxLastBits[2:0] indicates the number of valid bits in the last received byte. If this value is 000b, the whole byte is valid. + if (validBits) + { + *validBits = _validBits; + } + } + + // Tell about collisions + if (errorRegValue & 0x08) + { // CollErr + return STATUS_COLLISION; + } + + // Perform CRC_A validation if requested. + if (backData && backLen && checkCRC) + { + // In this case a MIFARE Classic NAK is not OK. + if ((*backLen == 1) && (_validBits == 4)) + { + return STATUS_MIFARE_NACK; + } + + // We need at least the CRC_A value and all 8 bits of the last byte must be received. + if ((*backLen < 2) || (_validBits != 0)) + { + return STATUS_CRC_WRONG; + } + + // Verify CRC_A - do our own calculation and store the control in controlBuffer. + uint8_t controlBuffer[2]; + n = PCD_CalculateCRC(&backData[0], *backLen - 2, &controlBuffer[0]); + if (n != STATUS_OK) + { + return n; + } + + if ((backData[*backLen - 2] != controlBuffer[0]) || (backData[*backLen - 1] != controlBuffer[1])) + { + return STATUS_CRC_WRONG; + } + } + + return STATUS_OK; +} // End PCD_CommunicateWithPICC() + +/* + * Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. + * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. + */ +uint8_t MFRC522::PICC_RequestA(uint8_t *bufferATQA, uint8_t *bufferSize) +{ + return PICC_REQA_or_WUPA(PICC_CMD_REQA, bufferATQA, bufferSize); +} // End PICC_RequestA() + +/** + * Transmits a Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. + * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. + */ +uint8_t MFRC522::PICC_WakeupA(uint8_t *bufferATQA, uint8_t *bufferSize) +{ + return PICC_REQA_or_WUPA(PICC_CMD_WUPA, bufferATQA, bufferSize); +} // End PICC_WakeupA() + +/* + * Transmits REQA or WUPA commands. + * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. + */ +uint8_t MFRC522::PICC_REQA_or_WUPA(uint8_t command, uint8_t *bufferATQA, uint8_t *bufferSize) +{ + uint8_t validBits; + uint8_t status; + + if (bufferATQA == NULL || *bufferSize < 2) + { // The ATQA response is 2 bytes long. + return STATUS_NO_ROOM; + } + + // ValuesAfterColl=1 => Bits received after collision are cleared. + PCD_ClrRegisterBits(CollReg, 0x80); + + // For REQA and WUPA we need the short frame format + // - transmit only 7 bits of the last (and only) byte. TxLastBits = BitFramingReg[2..0] + validBits = 7; + + status = PCD_TransceiveData(&command, 1, bufferATQA, bufferSize, &validBits); + if (status != STATUS_OK) + { + return status; + } + + if ((*bufferSize != 2) || (validBits != 0)) + { // ATQA must be exactly 16 bits. + return STATUS_ERROR; + } + + return STATUS_OK; +} // End PICC_REQA_or_WUPA() + +/* + * Transmits SELECT/ANTICOLLISION commands to select a single PICC. + */ +uint8_t MFRC522::PICC_Select(Uid *uid, uint8_t validBits) +{ + bool uidComplete; + bool selectDone; + bool useCascadeTag; + uint8_t cascadeLevel = 1; + uint8_t result; + uint8_t count; + uint8_t index; + uint8_t uidIndex; // The first index in uid->uidByte[] that is used in the current Cascade Level. + uint8_t currentLevelKnownBits; // The number of known UID bits in the current Cascade Level. + uint8_t buffer[9]; // The SELECT/ANTICOLLISION commands uses a 7 byte standard frame + 2 bytes CRC_A + uint8_t bufferUsed; // The number of bytes used in the buffer, ie the number of bytes to transfer to the FIFO. + uint8_t rxAlign; // Used in BitFramingReg. Defines the bit position for the first bit received. + uint8_t txLastBits; // Used in BitFramingReg. The number of valid bits in the last transmitted byte. + uint8_t *responseBuffer; + uint8_t responseLength; + + // Description of buffer structure: + // Byte 0: SEL Indicates the Cascade Level: PICC_CMD_SEL_CL1, PICC_CMD_SEL_CL2 or PICC_CMD_SEL_CL3 + // Byte 1: NVB Number of Valid Bits (in complete command, not just the UID): High nibble: complete bytes, Low nibble: Extra bits. + // Byte 2: UID-data or CT See explanation below. CT means Cascade Tag. + // Byte 3: UID-data + // Byte 4: UID-data + // Byte 5: UID-data + // Byte 6: BCC Block Check Character - XOR of bytes 2-5 + // Byte 7: CRC_A + // Byte 8: CRC_A + // The BCC and CRC_A is only transmitted if we know all the UID bits of the current Cascade Level. + // + // Description of bytes 2-5: (Section 6.5.4 of the ISO/IEC 14443-3 draft: UID contents and cascade levels) + // UID size Cascade level Byte2 Byte3 Byte4 Byte5 + // ======== ============= ===== ===== ===== ===== + // 4 bytes 1 uid0 uid1 uid2 uid3 + // 7 bytes 1 CT uid0 uid1 uid2 + // 2 uid3 uid4 uid5 uid6 + // 10 bytes 1 CT uid0 uid1 uid2 + // 2 CT uid3 uid4 uid5 + // 3 uid6 uid7 uid8 uid9 + + // Sanity checks + if (validBits > 80) + { + return STATUS_INVALID; + } + + // Prepare MFRC522 + // ValuesAfterColl=1 => Bits received after collision are cleared. + PCD_ClrRegisterBits(CollReg, 0x80); + + // Repeat Cascade Level loop until we have a complete UID. + uidComplete = false; + while ( ! uidComplete) + { + // Set the Cascade Level in the SEL byte, find out if we need to use the Cascade Tag in byte 2. + switch (cascadeLevel) + { + case 1: + buffer[0] = PICC_CMD_SEL_CL1; + uidIndex = 0; + useCascadeTag = validBits && (uid->size > 4); // When we know that the UID has more than 4 bytes + break; + + case 2: + buffer[0] = PICC_CMD_SEL_CL2; + uidIndex = 3; + useCascadeTag = validBits && (uid->size > 7); // When we know that the UID has more than 7 bytes + break; + + case 3: + buffer[0] = PICC_CMD_SEL_CL3; + uidIndex = 6; + useCascadeTag = false; // Never used in CL3. + break; + + default: + return STATUS_INTERNAL_ERROR; + //break; + } + + // How many UID bits are known in this Cascade Level? + if(validBits > (8 * uidIndex)) + { + currentLevelKnownBits = validBits - (8 * uidIndex); + } + else + { + currentLevelKnownBits = 0; + } + + // Copy the known bits from uid->uidByte[] to buffer[] + index = 2; // destination index in buffer[] + if (useCascadeTag) + { + buffer[index++] = PICC_CMD_CT; + } + + uint8_t bytesToCopy = currentLevelKnownBits / 8 + (currentLevelKnownBits % 8 ? 1 : 0); // The number of bytes needed to represent the known bits for this level. + if (bytesToCopy) + { + // Max 4 bytes in each Cascade Level. Only 3 left if we use the Cascade Tag + uint8_t maxBytes = useCascadeTag ? 3 : 4; + if (bytesToCopy > maxBytes) + { + bytesToCopy = maxBytes; + } + + for (count = 0; count < bytesToCopy; count++) + { + buffer[index++] = uid->uidByte[uidIndex + count]; + } + } + + // Now that the data has been copied we need to include the 8 bits in CT in currentLevelKnownBits + if (useCascadeTag) + { + currentLevelKnownBits += 8; + } + + // Repeat anti collision loop until we can transmit all UID bits + BCC and receive a SAK - max 32 iterations. + selectDone = false; + while ( ! selectDone) + { + // Find out how many bits and bytes to send and receive. + if (currentLevelKnownBits >= 32) + { // All UID bits in this Cascade Level are known. This is a SELECT. + //Serial.print("SELECT: currentLevelKnownBits="); Serial.println(currentLevelKnownBits, DEC); + buffer[1] = 0x70; // NVB - Number of Valid Bits: Seven whole bytes + + // Calulate BCC - Block Check Character + buffer[6] = buffer[2] ^ buffer[3] ^ buffer[4] ^ buffer[5]; + + // Calculate CRC_A + result = PCD_CalculateCRC(buffer, 7, &buffer[7]); + if (result != STATUS_OK) + { + return result; + } + + txLastBits = 0; // 0 => All 8 bits are valid. + bufferUsed = 9; + + // Store response in the last 3 bytes of buffer (BCC and CRC_A - not needed after tx) + responseBuffer = &buffer[6]; + responseLength = 3; + } + else + { // This is an ANTICOLLISION. + //Serial.print("ANTICOLLISION: currentLevelKnownBits="); Serial.println(currentLevelKnownBits, DEC); + txLastBits = currentLevelKnownBits % 8; + count = currentLevelKnownBits / 8; // Number of whole bytes in the UID part. + index = 2 + count; // Number of whole bytes: SEL + NVB + UIDs + buffer[1] = (index << 4) + txLastBits; // NVB - Number of Valid Bits + bufferUsed = index + (txLastBits ? 1 : 0); + + // Store response in the unused part of buffer + responseBuffer = &buffer[index]; + responseLength = sizeof(buffer) - index; + } + + // Set bit adjustments + rxAlign = txLastBits; // Having a seperate variable is overkill. But it makes the next line easier to read. + PCD_WriteRegister(BitFramingReg, (rxAlign << 4) + txLastBits); // RxAlign = BitFramingReg[6..4]. TxLastBits = BitFramingReg[2..0] + + // Transmit the buffer and receive the response. + result = PCD_TransceiveData(buffer, bufferUsed, responseBuffer, &responseLength, &txLastBits, rxAlign); + if (result == STATUS_COLLISION) + { // More than one PICC in the field => collision. + result = PCD_ReadRegister(CollReg); // CollReg[7..0] bits are: ValuesAfterColl reserved CollPosNotValid CollPos[4:0] + if (result & 0x20) + { // CollPosNotValid + return STATUS_COLLISION; // Without a valid collision position we cannot continue + } + + uint8_t collisionPos = result & 0x1F; // Values 0-31, 0 means bit 32. + if (collisionPos == 0) + { + collisionPos = 32; + } + + if (collisionPos <= currentLevelKnownBits) + { // No progress - should not happen + return STATUS_INTERNAL_ERROR; + } + + // Choose the PICC with the bit set. + currentLevelKnownBits = collisionPos; + count = (currentLevelKnownBits - 1) % 8; // The bit to modify + index = 1 + (currentLevelKnownBits / 8) + (count ? 1 : 0); // First byte is index 0. + buffer[index] |= (1 << count); + } + else if (result != STATUS_OK) + { + return result; + } + else + { // STATUS_OK + if (currentLevelKnownBits >= 32) + { // This was a SELECT. + selectDone = true; // No more anticollision + // We continue below outside the while. + } + else + { // This was an ANTICOLLISION. + // We now have all 32 bits of the UID in this Cascade Level + currentLevelKnownBits = 32; + // Run loop again to do the SELECT. + } + } + } // End of while ( ! selectDone) + + // We do not check the CBB - it was constructed by us above. + + // Copy the found UID bytes from buffer[] to uid->uidByte[] + index = (buffer[2] == PICC_CMD_CT) ? 3 : 2; // source index in buffer[] + bytesToCopy = (buffer[2] == PICC_CMD_CT) ? 3 : 4; + for (count = 0; count < bytesToCopy; count++) + { + uid->uidByte[uidIndex + count] = buffer[index++]; + } + + // Check response SAK (Select Acknowledge) + if (responseLength != 3 || txLastBits != 0) + { // SAK must be exactly 24 bits (1 byte + CRC_A). + return STATUS_ERROR; + } + + // Verify CRC_A - do our own calculation and store the control in buffer[2..3] - those bytes are not needed anymore. + result = PCD_CalculateCRC(responseBuffer, 1, &buffer[2]); + if (result != STATUS_OK) + { + return result; + } + + if ((buffer[2] != responseBuffer[1]) || (buffer[3] != responseBuffer[2])) + { + return STATUS_CRC_WRONG; + } + + if (responseBuffer[0] & 0x04) + { // Cascade bit set - UID not complete yes + cascadeLevel++; + } + else + { + uidComplete = true; + uid->sak = responseBuffer[0]; + } + } // End of while ( ! uidComplete) + + // Set correct uid->size + uid->size = 3 * cascadeLevel + 1; + + return STATUS_OK; +} // End PICC_Select() + +/* + * Instructs a PICC in state ACTIVE(*) to go to state HALT. + */ +uint8_t MFRC522::PICC_HaltA() +{ + uint8_t result; + uint8_t buffer[4]; + + // Build command buffer + buffer[0] = PICC_CMD_HLTA; + buffer[1] = 0; + + // Calculate CRC_A + result = PCD_CalculateCRC(buffer, 2, &buffer[2]); + if (result == STATUS_OK) + { + // Send the command. + // The standard says: + // If the PICC responds with any modulation during a period of 1 ms after the end of the frame containing the + // HLTA command, this response shall be interpreted as 'not acknowledge'. + // We interpret that this way: Only STATUS_TIMEOUT is an success. + result = PCD_TransceiveData(buffer, sizeof(buffer), NULL, 0); + if (result == STATUS_TIMEOUT) + { + result = STATUS_OK; + } + else if (result == STATUS_OK) + { // That is ironically NOT ok in this case ;-) + result = STATUS_ERROR; + } + } + + return result; +} // End PICC_HaltA() + + +///////////////////////////////////////////////////////////////////////////////////// +// Functions for communicating with MIFARE PICCs +///////////////////////////////////////////////////////////////////////////////////// + +/* + * Executes the MFRC522 MFAuthent command. + */ +uint8_t MFRC522::PCD_Authenticate(uint8_t command, uint8_t blockAddr, MIFARE_Key *key, Uid *uid) +{ + uint8_t i, waitIRq = 0x10; // IdleIRq + + // Build command buffer + uint8_t sendData[12]; + sendData[0] = command; + sendData[1] = blockAddr; + + for (i = 0; i < MF_KEY_SIZE; i++) + { // 6 key bytes + sendData[2+i] = key->keyByte[i]; + } + + for (i = 0; i < 4; i++) + { // The first 4 bytes of the UID + sendData[8+i] = uid->uidByte[i]; + } + + // Start the authentication. + return PCD_CommunicateWithPICC(PCD_MFAuthent, waitIRq, &sendData[0], sizeof(sendData)); +} // End PCD_Authenticate() + +/* + * Used to exit the PCD from its authenticated state. + * Remember to call this function after communicating with an authenticated PICC - otherwise no new communications can start. + */ +void MFRC522::PCD_StopCrypto1() +{ + // Clear MFCrypto1On bit + PCD_ClrRegisterBits(Status2Reg, 0x08); // Status2Reg[7..0] bits are: TempSensClear I2CForceHS reserved reserved MFCrypto1On ModemState[2:0] +} // End PCD_StopCrypto1() + +/* + * Reads 16 bytes (+ 2 bytes CRC_A) from the active PICC. + */ +uint8_t MFRC522::MIFARE_Read(uint8_t blockAddr, uint8_t *buffer, uint8_t *bufferSize) +{ + uint8_t result = STATUS_NO_ROOM; + + // Sanity check + if ((buffer == NULL) || (*bufferSize < 18)) + { + return result; + } + + // Build command buffer + buffer[0] = PICC_CMD_MF_READ; + buffer[1] = blockAddr; + + // Calculate CRC_A + result = PCD_CalculateCRC(buffer, 2, &buffer[2]); + if (result != STATUS_OK) + { + return result; + } + + // Transmit the buffer and receive the response, validate CRC_A. + return PCD_TransceiveData(buffer, 4, buffer, bufferSize, NULL, 0, true); +} // End MIFARE_Read() + +/* + * Writes 16 bytes to the active PICC. + */ +uint8_t MFRC522::MIFARE_Write(uint8_t blockAddr, uint8_t *buffer, uint8_t bufferSize) +{ + uint8_t result; + + // Sanity check + if (buffer == NULL || bufferSize < 16) + { + return STATUS_INVALID; + } + + // Mifare Classic protocol requires two communications to perform a write. + // Step 1: Tell the PICC we want to write to block blockAddr. + uint8_t cmdBuffer[2]; + cmdBuffer[0] = PICC_CMD_MF_WRITE; + cmdBuffer[1] = blockAddr; + // Adds CRC_A and checks that the response is MF_ACK. + result = PCD_MIFARE_Transceive(cmdBuffer, 2); + if (result != STATUS_OK) + { + return result; + } + + // Step 2: Transfer the data + // Adds CRC_A and checks that the response is MF_ACK. + result = PCD_MIFARE_Transceive(buffer, bufferSize); + if (result != STATUS_OK) + { + return result; + } + + return STATUS_OK; +} // End MIFARE_Write() + +/* + * Writes a 4 byte page to the active MIFARE Ultralight PICC. + */ +uint8_t MFRC522::MIFARE_UltralightWrite(uint8_t page, uint8_t *buffer, uint8_t bufferSize) +{ + uint8_t result; + + // Sanity check + if (buffer == NULL || bufferSize < 4) + { + return STATUS_INVALID; + } + + // Build commmand buffer + uint8_t cmdBuffer[6]; + cmdBuffer[0] = PICC_CMD_UL_WRITE; + cmdBuffer[1] = page; + memcpy(&cmdBuffer[2], buffer, 4); + + // Perform the write + result = PCD_MIFARE_Transceive(cmdBuffer, 6); // Adds CRC_A and checks that the response is MF_ACK. + if (result != STATUS_OK) + { + return result; + } + + return STATUS_OK; +} // End MIFARE_Ultralight_Write() + +/* + * MIFARE Decrement subtracts the delta from the value of the addressed block, and stores the result in a volatile memory. + */ +uint8_t MFRC522::MIFARE_Decrement(uint8_t blockAddr, uint32_t delta) +{ + return MIFARE_TwoStepHelper(PICC_CMD_MF_DECREMENT, blockAddr, delta); +} // End MIFARE_Decrement() + +/* + * MIFARE Increment adds the delta to the value of the addressed block, and stores the result in a volatile memory. + */ +uint8_t MFRC522::MIFARE_Increment(uint8_t blockAddr, uint32_t delta) +{ + return MIFARE_TwoStepHelper(PICC_CMD_MF_INCREMENT, blockAddr, delta); +} // End MIFARE_Increment() + +/** + * MIFARE Restore copies the value of the addressed block into a volatile memory. + */ +uint8_t MFRC522::MIFARE_Restore(uint8_t blockAddr) +{ + // The datasheet describes Restore as a two step operation, but does not explain what data to transfer in step 2. + // Doing only a single step does not work, so I chose to transfer 0L in step two. + return MIFARE_TwoStepHelper(PICC_CMD_MF_RESTORE, blockAddr, 0L); +} // End MIFARE_Restore() + +/* + * Helper function for the two-step MIFARE Classic protocol operations Decrement, Increment and Restore. + */ +uint8_t MFRC522::MIFARE_TwoStepHelper(uint8_t command, uint8_t blockAddr, uint32_t data) +{ + uint8_t result; + uint8_t cmdBuffer[2]; // We only need room for 2 bytes. + + // Step 1: Tell the PICC the command and block address + cmdBuffer[0] = command; + cmdBuffer[1] = blockAddr; + + // Adds CRC_A and checks that the response is MF_ACK. + result = PCD_MIFARE_Transceive(cmdBuffer, 2); + if (result != STATUS_OK) + { + return result; + } + + // Step 2: Transfer the data + // Adds CRC_A and accept timeout as success. + result = PCD_MIFARE_Transceive((uint8_t *) &data, 4, true); + if (result != STATUS_OK) + { + return result; + } + + return STATUS_OK; +} // End MIFARE_TwoStepHelper() + +/* + * MIFARE Transfer writes the value stored in the volatile memory into one MIFARE Classic block. + */ +uint8_t MFRC522::MIFARE_Transfer(uint8_t blockAddr) +{ + uint8_t cmdBuffer[2]; // We only need room for 2 bytes. + + // Tell the PICC we want to transfer the result into block blockAddr. + cmdBuffer[0] = PICC_CMD_MF_TRANSFER; + cmdBuffer[1] = blockAddr; + + // Adds CRC_A and checks that the response is MF_ACK. + return PCD_MIFARE_Transceive(cmdBuffer, 2); +} // End MIFARE_Transfer() + + +///////////////////////////////////////////////////////////////////////////////////// +// Support functions +///////////////////////////////////////////////////////////////////////////////////// + +/* + * Wrapper for MIFARE protocol communication. + * Adds CRC_A, executes the Transceive command and checks that the response is MF_ACK or a timeout. + */ +uint8_t MFRC522::PCD_MIFARE_Transceive(uint8_t *sendData, uint8_t sendLen, bool acceptTimeout) +{ + uint8_t result; + uint8_t cmdBuffer[18]; // We need room for 16 bytes data and 2 bytes CRC_A. + + // Sanity check + if (sendData == NULL || sendLen > 16) + { + return STATUS_INVALID; + } + + // Copy sendData[] to cmdBuffer[] and add CRC_A + memcpy(cmdBuffer, sendData, sendLen); + result = PCD_CalculateCRC(cmdBuffer, sendLen, &cmdBuffer[sendLen]); + if (result != STATUS_OK) + { + return result; + } + + sendLen += 2; + + // Transceive the data, store the reply in cmdBuffer[] + uint8_t waitIRq = 0x30; // RxIRq and IdleIRq + uint8_t cmdBufferSize = sizeof(cmdBuffer); + uint8_t validBits = 0; + result = PCD_CommunicateWithPICC(PCD_Transceive, waitIRq, cmdBuffer, sendLen, cmdBuffer, &cmdBufferSize, &validBits); + if (acceptTimeout && result == STATUS_TIMEOUT) + { + return STATUS_OK; + } + + if (result != STATUS_OK) + { + return result; + } + + // The PICC must reply with a 4 bit ACK + if (cmdBufferSize != 1 || validBits != 4) + { + return STATUS_ERROR; + } + + if (cmdBuffer[0] != MF_ACK) + { + return STATUS_MIFARE_NACK; + } + + return STATUS_OK; +} // End PCD_MIFARE_Transceive() + + +/* + * Translates the SAK (Select Acknowledge) to a PICC type. + */ +uint8_t MFRC522::PICC_GetType(uint8_t sak) +{ + uint8_t retType = PICC_TYPE_UNKNOWN; + + if (sak & 0x04) + { // UID not complete + retType = PICC_TYPE_NOT_COMPLETE; + } + else + { + switch (sak) + { + case 0x09: retType = PICC_TYPE_MIFARE_MINI; break; + case 0x08: retType = PICC_TYPE_MIFARE_1K; break; + case 0x18: retType = PICC_TYPE_MIFARE_4K; break; + case 0x00: retType = PICC_TYPE_MIFARE_UL; break; + case 0x10: + case 0x11: retType = PICC_TYPE_MIFARE_PLUS; break; + case 0x01: retType = PICC_TYPE_TNP3XXX; break; + default: + if (sak & 0x20) + { + retType = PICC_TYPE_ISO_14443_4; + } + else if (sak & 0x40) + { + retType = PICC_TYPE_ISO_18092; + } + break; + } + } + + return (retType); +} // End PICC_GetType() + +/* + * Returns a string pointer to the PICC type name. + */ +char* MFRC522::PICC_GetTypeName(uint8_t piccType) +{ + if(piccType == PICC_TYPE_NOT_COMPLETE) + { + piccType = MFRC522_MaxPICCs - 1; + } + + return((char *) _TypeNamePICC[piccType]); +} // End PICC_GetTypeName() + +/* + * Returns a string pointer to a status code name. + */ +char* MFRC522::GetStatusCodeName(uint8_t code) +{ + return((char *) _ErrorMessage[code]); +} // End GetStatusCodeName() + +/* + * Calculates the bit pattern needed for the specified access bits. In the [C1 C2 C3] tupples C1 is MSB (=4) and C3 is LSB (=1). + */ +void MFRC522::MIFARE_SetAccessBits(uint8_t *accessBitBuffer, + uint8_t g0, + uint8_t g1, + uint8_t g2, + uint8_t g3) +{ + uint8_t c1 = ((g3 & 4) << 1) | ((g2 & 4) << 0) | ((g1 & 4) >> 1) | ((g0 & 4) >> 2); + uint8_t c2 = ((g3 & 2) << 2) | ((g2 & 2) << 1) | ((g1 & 2) << 0) | ((g0 & 2) >> 1); + uint8_t c3 = ((g3 & 1) << 3) | ((g2 & 1) << 2) | ((g1 & 1) << 1) | ((g0 & 1) << 0); + + accessBitBuffer[0] = (~c2 & 0xF) << 4 | (~c1 & 0xF); + accessBitBuffer[1] = c1 << 4 | (~c3 & 0xF); + accessBitBuffer[2] = c3 << 4 | c2; +} // End MIFARE_SetAccessBits() + +///////////////////////////////////////////////////////////////////////////////////// +// Convenience functions - does not add extra functionality +///////////////////////////////////////////////////////////////////////////////////// + +/* + * Returns true if a PICC responds to PICC_CMD_REQA. + * Only "new" cards in state IDLE are invited. Sleeping cards in state HALT are ignored. + */ +bool MFRC522::PICC_IsNewCardPresent(void) +{ + uint8_t bufferATQA[2]; + uint8_t bufferSize = sizeof(bufferATQA); + uint8_t result = PICC_RequestA(bufferATQA, &bufferSize); + return ((result == STATUS_OK) || (result == STATUS_COLLISION)); +} // End PICC_IsNewCardPresent() + +/* + * Simple wrapper around PICC_Select. + */ +bool MFRC522::PICC_ReadCardSerial(void) +{ + uint8_t result = PICC_Select(&uid); + return (result == STATUS_OK); +} // End PICC_ReadCardSerial()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MFRC522.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,785 @@ +/** + * MFRC522.h - Library to use ARDUINO RFID MODULE KIT 13.56 MHZ WITH TAGS SPI W AND R BY COOQROBOT. + * Based on code Dr.Leong ( WWW.B2CQSHOP.COM ) + * Created by Miguel Balboa (circuitito.com), Jan, 2012. + * Rewritten by Soren Thing Andersen (access.thing.dk), fall of 2013 (Translation to English, refactored, comments, anti collision, cascade levels.) + * Ported to mbed by Martin Olejar, Dec, 2013 + * + * Please read this file for an overview and then MFRC522.cpp for comments on the specific functions. + * Search for "mf-rc522" on ebay.com to purchase the MF-RC522 board. + * + * There are three hardware components involved: + * 1) The micro controller: An Arduino + * 2) The PCD (short for Proximity Coupling Device): NXP MFRC522 Contactless Reader IC + * 3) The PICC (short for Proximity Integrated Circuit Card): A card or tag using the ISO 14443A interface, eg Mifare or NTAG203. + * + * The microcontroller and card reader uses SPI for communication. + * The protocol is described in the MFRC522 datasheet: http://www.nxp.com/documents/data_sheet/MFRC522.pdf + * + * The card reader and the tags communicate using a 13.56MHz electromagnetic field. + * The protocol is defined in ISO/IEC 14443-3 Identification cards -- Contactless integrated circuit cards -- Proximity cards -- Part 3: Initialization and anticollision". + * A free version of the final draft can be found at http://wg8.de/wg8n1496_17n3613_Ballot_FCD14443-3.pdf + * Details are found in chapter 6, Type A: Initialization and anticollision. + * + * If only the PICC UID is wanted, the above documents has all the needed information. + * To read and write from MIFARE PICCs, the MIFARE protocol is used after the PICC has been selected. + * The MIFARE Classic chips and protocol is described in the datasheets: + * 1K: http://www.nxp.com/documents/data_sheet/MF1S503x.pdf + * 4K: http://www.nxp.com/documents/data_sheet/MF1S703x.pdf + * Mini: http://www.idcardmarket.com/download/mifare_S20_datasheet.pdf + * The MIFARE Ultralight chip and protocol is described in the datasheets: + * Ultralight: http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf + * Ultralight C: http://www.nxp.com/documents/short_data_sheet/MF0ICU2_SDS.pdf + * + * MIFARE Classic 1K (MF1S503x): + * Has 16 sectors * 4 blocks/sector * 16 bytes/block = 1024 bytes. + * The blocks are numbered 0-63. + * Block 3 in each sector is the Sector Trailer. See http://www.nxp.com/documents/data_sheet/MF1S503x.pdf sections 8.6 and 8.7: + * Bytes 0-5: Key A + * Bytes 6-8: Access Bits + * Bytes 9: User data + * Bytes 10-15: Key B (or user data) + * Block 0 is read only manufacturer data. + * To access a block, an authentication using a key from the block's sector must be performed first. + * Example: To read from block 10, first authenticate using a key from sector 3 (blocks 8-11). + * All keys are set to FFFFFFFFFFFFh at chip delivery. + * Warning: Please read section 8.7 "Memory Access". It includes this text: if the PICC detects a format violation the whole sector is irreversibly blocked. + * To use a block in "value block" mode (for Increment/Decrement operations) you need to change the sector trailer. Use PICC_SetAccessBits() to calculate the bit patterns. + * MIFARE Classic 4K (MF1S703x): + * Has (32 sectors * 4 blocks/sector + 8 sectors * 16 blocks/sector) * 16 bytes/block = 4096 bytes. + * The blocks are numbered 0-255. + * The last block in each sector is the Sector Trailer like above. + * MIFARE Classic Mini (MF1 IC S20): + * Has 5 sectors * 4 blocks/sector * 16 bytes/block = 320 bytes. + * The blocks are numbered 0-19. + * The last block in each sector is the Sector Trailer like above. + * + * MIFARE Ultralight (MF0ICU1): + * Has 16 pages of 4 bytes = 64 bytes. + * Pages 0 + 1 is used for the 7-byte UID. + * Page 2 contains the last chech digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) + * Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. + * Pages 4-15 are read/write unless blocked by the lock bytes in page 2. + * MIFARE Ultralight C (MF0ICU2): + * Has 48 pages of 4 bytes = 64 bytes. + * Pages 0 + 1 is used for the 7-byte UID. + * Page 2 contains the last chech digit for the UID, one byte manufacturer internal data, and the lock bytes (see http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf section 8.5.2) + * Page 3 is OTP, One Time Programmable bits. Once set to 1 they cannot revert to 0. + * Pages 4-39 are read/write unless blocked by the lock bytes in page 2. + * Page 40 Lock bytes + * Page 41 16 bit one way counter + * Pages 42-43 Authentication configuration + * Pages 44-47 Authentication key + */ +#ifndef MFRC522_h +#define MFRC522_h + +#include "mbed.h" + +/** +* MFRC522 example +* +* @code +* #include "mbed.h" +* #include "MFRC522.h" +* +* //KL25Z Pins for MFRC522 SPI interface +* #define SPI_MOSI PTC6 +* #define SPI_MISO PTC7 +* #define SPI_SCLK PTC5 +* #define SPI_CS PTC4 +* // KL25Z Pin for MFRC522 reset +* #define MF_RESET PTC3 +* // KL25Z Pins for Debug UART port +* #define UART_RX PTA1 +* #define UART_TX PTA2 +* +* DigitalOut LedRed (LED_RED); +* DigitalOut LedGreen (LED_GREEN); +* +* Serial DebugUART(UART_TX, UART_RX); +* MFRC522 RfChip (SPI_MOSI, SPI_MISO, SPI_SCLK, SPI_CS, MF_RESET); +* +* int main(void) { +* // Set debug UART speed +* DebugUART.baud(115200); +* +* // Init. RC522 Chip +* RfChip.PCD_Init(); +* +* while (true) { +* LedRed = 1; +* LedGreen = 1; +* +* // Look for new cards +* if ( ! RfChip.PICC_IsNewCardPresent()) +* { +* wait_ms(500); +* continue; +* } +* +* LedRed = 0; +* +* // Select one of the cards +* if ( ! RfChip.PICC_ReadCardSerial()) +* { +* wait_ms(500); +* continue; +* } +* +* LedRed = 1; +* LedGreen = 0; +* +* // Print Card UID +* printf("Card UID: "); +* for (uint8_t i = 0; i < RfChip.uid.size; i++) +* { +* printf(" %X02", RfChip.uid.uidByte[i]); +* } +* printf("\n\r"); +* +* // Print Card type +* uint8_t piccType = RfChip.PICC_GetType(RfChip.uid.sak); +* printf("PICC Type: %s \n\r", RfChip.PICC_GetTypeName(piccType)); +* wait_ms(1000); +* } +* } +* @endcode +*/ + +class MFRC522 { +public: + + /** + * MFRC522 registers (described in chapter 9 of the datasheet). + * When using SPI all addresses are shifted one bit left in the "SPI address byte" (section 8.1.2.3) + */ + enum PCD_Register { + // Page 0: Command and status + // 0x00 // reserved for future use + CommandReg = 0x01 << 1, // starts and stops command execution + ComIEnReg = 0x02 << 1, // enable and disable interrupt request control bits + DivIEnReg = 0x03 << 1, // enable and disable interrupt request control bits + ComIrqReg = 0x04 << 1, // interrupt request bits + DivIrqReg = 0x05 << 1, // interrupt request bits + ErrorReg = 0x06 << 1, // error bits showing the error status of the last command executed + Status1Reg = 0x07 << 1, // communication status bits + Status2Reg = 0x08 << 1, // receiver and transmitter status bits + FIFODataReg = 0x09 << 1, // input and output of 64 byte FIFO buffer + FIFOLevelReg = 0x0A << 1, // number of bytes stored in the FIFO buffer + WaterLevelReg = 0x0B << 1, // level for FIFO underflow and overflow warning + ControlReg = 0x0C << 1, // miscellaneous control registers + BitFramingReg = 0x0D << 1, // adjustments for bit-oriented frames + CollReg = 0x0E << 1, // bit position of the first bit-collision detected on the RF interface + // 0x0F // reserved for future use + + // Page 1:Command + // 0x10 // reserved for future use + ModeReg = 0x11 << 1, // defines general modes for transmitting and receiving + TxModeReg = 0x12 << 1, // defines transmission data rate and framing + RxModeReg = 0x13 << 1, // defines reception data rate and framing + TxControlReg = 0x14 << 1, // controls the logical behavior of the antenna driver pins TX1 and TX2 + TxASKReg = 0x15 << 1, // controls the setting of the transmission modulation + TxSelReg = 0x16 << 1, // selects the internal sources for the antenna driver + RxSelReg = 0x17 << 1, // selects internal receiver settings + RxThresholdReg = 0x18 << 1, // selects thresholds for the bit decoder + DemodReg = 0x19 << 1, // defines demodulator settings + // 0x1A // reserved for future use + // 0x1B // reserved for future use + MfTxReg = 0x1C << 1, // controls some MIFARE communication transmit parameters + MfRxReg = 0x1D << 1, // controls some MIFARE communication receive parameters + // 0x1E // reserved for future use + SerialSpeedReg = 0x1F << 1, // selects the speed of the serial UART interface + + // Page 2: Configuration + // 0x20 // reserved for future use + CRCResultRegH = 0x21 << 1, // shows the MSB and LSB values of the CRC calculation + CRCResultRegL = 0x22 << 1, + // 0x23 // reserved for future use + ModWidthReg = 0x24 << 1, // controls the ModWidth setting? + // 0x25 // reserved for future use + RFCfgReg = 0x26 << 1, // configures the receiver gain + GsNReg = 0x27 << 1, // selects the conductance of the antenna driver pins TX1 and TX2 for modulation + CWGsPReg = 0x28 << 1, // defines the conductance of the p-driver output during periods of no modulation + ModGsPReg = 0x29 << 1, // defines the conductance of the p-driver output during periods of modulation + TModeReg = 0x2A << 1, // defines settings for the internal timer + TPrescalerReg = 0x2B << 1, // the lower 8 bits of the TPrescaler value. The 4 high bits are in TModeReg. + TReloadRegH = 0x2C << 1, // defines the 16-bit timer reload value + TReloadRegL = 0x2D << 1, + TCntValueRegH = 0x2E << 1, // shows the 16-bit timer value + TCntValueRegL = 0x2F << 1, + + // Page 3:Test Registers + // 0x30 // reserved for future use + TestSel1Reg = 0x31 << 1, // general test signal configuration + TestSel2Reg = 0x32 << 1, // general test signal configuration + TestPinEnReg = 0x33 << 1, // enables pin output driver on pins D1 to D7 + TestPinValueReg = 0x34 << 1, // defines the values for D1 to D7 when it is used as an I/O bus + TestBusReg = 0x35 << 1, // shows the status of the internal test bus + AutoTestReg = 0x36 << 1, // controls the digital self test + VersionReg = 0x37 << 1, // shows the software version + AnalogTestReg = 0x38 << 1, // controls the pins AUX1 and AUX2 + TestDAC1Reg = 0x39 << 1, // defines the test value for TestDAC1 + TestDAC2Reg = 0x3A << 1, // defines the test value for TestDAC2 + TestADCReg = 0x3B << 1 // shows the value of ADC I and Q channels + // 0x3C // reserved for production tests + // 0x3D // reserved for production tests + // 0x3E // reserved for production tests + // 0x3F // reserved for production tests + }; + + // MFRC522 commands Described in chapter 10 of the datasheet. + enum PCD_Command { + PCD_Idle = 0x00, // no action, cancels current command execution + PCD_Mem = 0x01, // stores 25 bytes into the internal buffer + PCD_GenerateRandomID = 0x02, // generates a 10-byte random ID number + PCD_CalcCRC = 0x03, // activates the CRC coprocessor or performs a self test + PCD_Transmit = 0x04, // transmits data from the FIFO buffer + PCD_NoCmdChange = 0x07, // no command change, can be used to modify the CommandReg register bits without affecting the command, for example, the PowerDown bit + PCD_Receive = 0x08, // activates the receiver circuits + PCD_Transceive = 0x0C, // transmits data from FIFO buffer to antenna and automatically activates the receiver after transmission + PCD_MFAuthent = 0x0E, // performs the MIFARE standard authentication as a reader + PCD_SoftReset = 0x0F // resets the MFRC522 + }; + + // Commands sent to the PICC. + enum PICC_Command { + // The commands used by the PCD to manage communication with several PICCs (ISO 14443-3, Type A, section 6.4) + PICC_CMD_REQA = 0x26, // REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. + PICC_CMD_WUPA = 0x52, // Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. + PICC_CMD_CT = 0x88, // Cascade Tag. Not really a command, but used during anti collision. + PICC_CMD_SEL_CL1 = 0x93, // Anti collision/Select, Cascade Level 1 + PICC_CMD_SEL_CL2 = 0x95, // Anti collision/Select, Cascade Level 1 + PICC_CMD_SEL_CL3 = 0x97, // Anti collision/Select, Cascade Level 1 + PICC_CMD_HLTA = 0x50, // HaLT command, Type A. Instructs an ACTIVE PICC to go to state HALT. + + // The commands used for MIFARE Classic (from http://www.nxp.com/documents/data_sheet/MF1S503x.pdf, Section 9) + // Use PCD_MFAuthent to authenticate access to a sector, then use these commands to read/write/modify the blocks on the sector. + // The read/write commands can also be used for MIFARE Ultralight. + PICC_CMD_MF_AUTH_KEY_A = 0x60, // Perform authentication with Key A + PICC_CMD_MF_AUTH_KEY_B = 0x61, // Perform authentication with Key B + PICC_CMD_MF_READ = 0x30, // Reads one 16 byte block from the authenticated sector of the PICC. Also used for MIFARE Ultralight. + PICC_CMD_MF_WRITE = 0xA0, // Writes one 16 byte block to the authenticated sector of the PICC. Called "COMPATIBILITY WRITE" for MIFARE Ultralight. + PICC_CMD_MF_DECREMENT = 0xC0, // Decrements the contents of a block and stores the result in the internal data register. + PICC_CMD_MF_INCREMENT = 0xC1, // Increments the contents of a block and stores the result in the internal data register. + PICC_CMD_MF_RESTORE = 0xC2, // Reads the contents of a block into the internal data register. + PICC_CMD_MF_TRANSFER = 0xB0, // Writes the contents of the internal data register to a block. + + // The commands used for MIFARE Ultralight (from http://www.nxp.com/documents/data_sheet/MF0ICU1.pdf, Section 8.6) + // The PICC_CMD_MF_READ and PICC_CMD_MF_WRITE can also be used for MIFARE Ultralight. + PICC_CMD_UL_WRITE = 0xA2 // Writes one 4 byte page to the PICC. + }; + + // MIFARE constants that does not fit anywhere else + enum MIFARE_Misc { + MF_ACK = 0xA, // The MIFARE Classic uses a 4 bit ACK/NAK. Any other value than 0xA is NAK. + MF_KEY_SIZE = 6 // A Mifare Crypto1 key is 6 bytes. + }; + + // PICC types we can detect. Remember to update PICC_GetTypeName() if you add more. + enum PICC_Type { + PICC_TYPE_UNKNOWN = 0, + PICC_TYPE_ISO_14443_4 = 1, // PICC compliant with ISO/IEC 14443-4 + PICC_TYPE_ISO_18092 = 2, // PICC compliant with ISO/IEC 18092 (NFC) + PICC_TYPE_MIFARE_MINI = 3, // MIFARE Classic protocol, 320 bytes + PICC_TYPE_MIFARE_1K = 4, // MIFARE Classic protocol, 1KB + PICC_TYPE_MIFARE_4K = 5, // MIFARE Classic protocol, 4KB + PICC_TYPE_MIFARE_UL = 6, // MIFARE Ultralight or Ultralight C + PICC_TYPE_MIFARE_PLUS = 7, // MIFARE Plus + PICC_TYPE_TNP3XXX = 8, // Only mentioned in NXP AN 10833 MIFARE Type Identification Procedure + PICC_TYPE_NOT_COMPLETE = 255 // SAK indicates UID is not complete. + }; + + // Return codes from the functions in this class. Remember to update GetStatusCodeName() if you add more. + enum StatusCode { + STATUS_OK = 1, // Success + STATUS_ERROR = 2, // Error in communication + STATUS_COLLISION = 3, // Collision detected + STATUS_TIMEOUT = 4, // Timeout in communication. + STATUS_NO_ROOM = 5, // A buffer is not big enough. + STATUS_INTERNAL_ERROR = 6, // Internal error in the code. Should not happen ;-) + STATUS_INVALID = 7, // Invalid argument. + STATUS_CRC_WRONG = 8, // The CRC_A does not match + STATUS_MIFARE_NACK = 9 // A MIFARE PICC responded with NAK. + }; + + // A struct used for passing the UID of a PICC. + typedef struct { + uint8_t size; // Number of bytes in the UID. 4, 7 or 10. + uint8_t uidByte[10]; + uint8_t sak; // The SAK (Select acknowledge) byte returned from the PICC after successful selection. + } Uid; + + // A struct used for passing a MIFARE Crypto1 key + typedef struct { + uint8_t keyByte[MF_KEY_SIZE]; + } MIFARE_Key; + + // Member variables + Uid uid; // Used by PICC_ReadCardSerial(). + + // Size of the MFRC522 FIFO + static const uint8_t FIFO_SIZE = 64; // The FIFO is 64 bytes. + + /** + * MFRC522 constructor + * + * @param mosi SPI MOSI pin + * @param miso SPI MISO pin + * @param sclk SPI SCLK pin + * @param cs SPI CS pin + * @param reset Reset pin + */ + MFRC522(PinName mosi, PinName miso, PinName sclk, PinName cs, PinName reset); + + /** + * MFRC522 destructor + */ + ~MFRC522(); + + + // ************************************************************************************ + //! @name Functions for manipulating the MFRC522 + // ************************************************************************************ + //@{ + + /** + * Initializes the MFRC522 chip. + */ + void PCD_Init (void); + + /** + * Performs a soft reset on the MFRC522 chip and waits for it to be ready again. + */ + void PCD_Reset (void); + + /** + * Turns the antenna on by enabling pins TX1 and TX2. + * After a reset these pins disabled. + */ + void PCD_AntennaOn (void); + + /** + * Writes a byte to the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.2. + * + * @param reg The register to write to. One of the PCD_Register enums. + * @param value The value to write. + */ + void PCD_WriteRegister (uint8_t reg, uint8_t value); + + /** + * Writes a number of bytes to the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.2. + * + * @param reg The register to write to. One of the PCD_Register enums. + * @param count The number of bytes to write to the register + * @param values The values to write. Byte array. + */ + void PCD_WriteRegister (uint8_t reg, uint8_t count, uint8_t *values); + + /** + * Reads a byte from the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.2. + * + * @param reg The register to read from. One of the PCD_Register enums. + * @returns Register value + */ + uint8_t PCD_ReadRegister (uint8_t reg); + + /** + * Reads a number of bytes from the specified register in the MFRC522 chip. + * The interface is described in the datasheet section 8.1.2. + * + * @param reg The register to read from. One of the PCD_Register enums. + * @param count The number of bytes to read. + * @param values Byte array to store the values in. + * @param rxAlign Only bit positions rxAlign..7 in values[0] are updated. + */ + void PCD_ReadRegister (uint8_t reg, uint8_t count, uint8_t *values, uint8_t rxAlign = 0); + + /** + * Sets the bits given in mask in register reg. + * + * @param reg The register to update. One of the PCD_Register enums. + * @param mask The bits to set. + */ + void PCD_SetRegisterBits(uint8_t reg, uint8_t mask); + + /** + * Clears the bits given in mask from register reg. + * + * @param reg The register to update. One of the PCD_Register enums. + * @param mask The bits to clear. + */ + void PCD_ClrRegisterBits(uint8_t reg, uint8_t mask); + + /** + * Use the CRC coprocessor in the MFRC522 to calculate a CRC_A. + * + * @param data Pointer to the data to transfer to the FIFO for CRC calculation. + * @param length The number of bytes to transfer. + * @param result Pointer to result buffer. Result is written to result[0..1], low byte first. + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PCD_CalculateCRC (uint8_t *data, uint8_t length, uint8_t *result); + + /** + * Executes the Transceive command. + * CRC validation can only be done if backData and backLen are specified. + * + * @param sendData Pointer to the data to transfer to the FIFO. + * @param sendLen Number of bytes to transfer to the FIFO. + * @param backData NULL or pointer to buffer if data should be read back after executing the command. + * @param backLen Max number of bytes to write to *backData. Out: The number of bytes returned. + * @param validBits The number of valid bits in the last byte. 0 for 8 valid bits. Default NULL. + * @param rxAlign Defines the bit position in backData[0] for the first bit received. Default 0. + * @param checkCRC True => The last two bytes of the response is assumed to be a CRC_A that must be validated. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PCD_TransceiveData (uint8_t *sendData, + uint8_t sendLen, + uint8_t *backData, + uint8_t *backLen, + uint8_t *validBits = NULL, + uint8_t rxAlign = 0, + bool checkCRC = false); + + + /** + * Transfers data to the MFRC522 FIFO, executes a commend, waits for completion and transfers data back from the FIFO. + * CRC validation can only be done if backData and backLen are specified. + * + * @param command The command to execute. One of the PCD_Command enums. + * @param waitIRq The bits in the ComIrqReg register that signals successful completion of the command. + * @param sendData Pointer to the data to transfer to the FIFO. + * @param sendLen Number of bytes to transfer to the FIFO. + * @param backData NULL or pointer to buffer if data should be read back after executing the command. + * @param backLen In: Max number of bytes to write to *backData. Out: The number of bytes returned. + * @param validBits In/Out: The number of valid bits in the last byte. 0 for 8 valid bits. + * @param rxAlign In: Defines the bit position in backData[0] for the first bit received. Default 0. + * @param checkCRC In: True => The last two bytes of the response is assumed to be a CRC_A that must be validated. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PCD_CommunicateWithPICC(uint8_t command, + uint8_t waitIRq, + uint8_t *sendData, + uint8_t sendLen, + uint8_t *backData = NULL, + uint8_t *backLen = NULL, + uint8_t *validBits = NULL, + uint8_t rxAlign = 0, + bool checkCRC = false); + + /** + * Transmits a REQuest command, Type A. Invites PICCs in state IDLE to go to READY and prepare for anticollision or selection. 7 bit frame. + * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. + * + * @param bufferATQA The buffer to store the ATQA (Answer to request) in + * @param bufferSize Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PICC_RequestA (uint8_t *bufferATQA, uint8_t *bufferSize); + + /** + * Transmits a Wake-UP command, Type A. Invites PICCs in state IDLE and HALT to go to READY(*) and prepare for anticollision or selection. 7 bit frame. + * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. + * + * @param bufferATQA The buffer to store the ATQA (Answer to request) in + * @param bufferSize Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PICC_WakeupA (uint8_t *bufferATQA, uint8_t *bufferSize); + + /** + * Transmits REQA or WUPA commands. + * Beware: When two PICCs are in the field at the same time I often get STATUS_TIMEOUT - probably due do bad antenna design. + * + * @param command The command to send - PICC_CMD_REQA or PICC_CMD_WUPA + * @param bufferATQA The buffer to store the ATQA (Answer to request) in + * @param bufferSize Buffer size, at least two bytes. Also number of bytes returned if STATUS_OK. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PICC_REQA_or_WUPA (uint8_t command, uint8_t *bufferATQA, uint8_t *bufferSize); + + /** + * Transmits SELECT/ANTICOLLISION commands to select a single PICC. + * Before calling this function the PICCs must be placed in the READY(*) state by calling PICC_RequestA() or PICC_WakeupA(). + * On success: + * - The chosen PICC is in state ACTIVE(*) and all other PICCs have returned to state IDLE/HALT. (Figure 7 of the ISO/IEC 14443-3 draft.) + * - The UID size and value of the chosen PICC is returned in *uid along with the SAK. + * + * A PICC UID consists of 4, 7 or 10 bytes. + * Only 4 bytes can be specified in a SELECT command, so for the longer UIDs two or three iterations are used: + * + * UID size Number of UID bytes Cascade levels Example of PICC + * ======== =================== ============== =============== + * single 4 1 MIFARE Classic + * double 7 2 MIFARE Ultralight + * triple 10 3 Not currently in use? + * + * + * @param uid Pointer to Uid struct. Normally output, but can also be used to supply a known UID. + * @param validBits The number of known UID bits supplied in *uid. Normally 0. If set you must also supply uid->size. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PICC_Select (Uid *uid, uint8_t validBits = 0); + + /** + * Instructs a PICC in state ACTIVE(*) to go to state HALT. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PICC_HaltA (void); + + // ************************************************************************************ + //@} + + + // ************************************************************************************ + //! @name Functions for communicating with MIFARE PICCs + // ************************************************************************************ + //@{ + + /** + * Executes the MFRC522 MFAuthent command. + * This command manages MIFARE authentication to enable a secure communication to any MIFARE Mini, MIFARE 1K and MIFARE 4K card. + * The authentication is described in the MFRC522 datasheet section 10.3.1.9 and http://www.nxp.com/documents/data_sheet/MF1S503x.pdf section 10.1. + * For use with MIFARE Classic PICCs. + * The PICC must be selected - ie in state ACTIVE(*) - before calling this function. + * Remember to call PCD_StopCrypto1() after communicating with the authenticated PICC - otherwise no new communications can start. + * + * All keys are set to FFFFFFFFFFFFh at chip delivery. + * + * @param command PICC_CMD_MF_AUTH_KEY_A or PICC_CMD_MF_AUTH_KEY_B + * @param blockAddr The block number. See numbering in the comments in the .h file. + * @param key Pointer to the Crypteo1 key to use (6 bytes) + * @param uid Pointer to Uid struct. The first 4 bytes of the UID is used. + * + * @return STATUS_OK on success, STATUS_??? otherwise. Probably STATUS_TIMEOUT if you supply the wrong key. + */ + uint8_t PCD_Authenticate (uint8_t command, uint8_t blockAddr, MIFARE_Key *key, Uid *uid); + + /** + * Used to exit the PCD from its authenticated state. + * Remember to call this function after communicating with an authenticated PICC - otherwise no new communications can start. + */ + void PCD_StopCrypto1 (void); + + /** + * Reads 16 bytes (+ 2 bytes CRC_A) from the active PICC. + * + * For MIFARE Classic the sector containing the block must be authenticated before calling this function. + * + * For MIFARE Ultralight only addresses 00h to 0Fh are decoded. + * The MF0ICU1 returns a NAK for higher addresses. + * The MF0ICU1 responds to the READ command by sending 16 bytes starting from the page address defined by the command argument. + * For example; if blockAddr is 03h then pages 03h, 04h, 05h, 06h are returned. + * A roll-back is implemented: If blockAddr is 0Eh, then the contents of pages 0Eh, 0Fh, 00h and 01h are returned. + * + * The buffer must be at least 18 bytes because a CRC_A is also returned. + * Checks the CRC_A before returning STATUS_OK. + * + * @param blockAddr MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The first page to return data from. + * @param buffer The buffer to store the data in + * @param bufferSize Buffer size, at least 18 bytes. Also number of bytes returned if STATUS_OK. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_Read (uint8_t blockAddr, uint8_t *buffer, uint8_t *bufferSize); + + /** + * Writes 16 bytes to the active PICC. + * + * For MIFARE Classic the sector containing the block must be authenticated before calling this function. + * + * For MIFARE Ultralight the opretaion is called "COMPATIBILITY WRITE". + * Even though 16 bytes are transferred to the Ultralight PICC, only the least significant 4 bytes (bytes 0 to 3) + * are written to the specified address. It is recommended to set the remaining bytes 04h to 0Fh to all logic 0. + * + * @param blockAddr MIFARE Classic: The block (0-0xff) number. MIFARE Ultralight: The page (2-15) to write to. + * @param buffer The 16 bytes to write to the PICC + * @param bufferSize Buffer size, must be at least 16 bytes. Exactly 16 bytes are written. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_Write (uint8_t blockAddr, uint8_t *buffer, uint8_t bufferSize); + + /** + * Writes a 4 byte page to the active MIFARE Ultralight PICC. + * + * @param page The page (2-15) to write to. + * @param buffer The 4 bytes to write to the PICC + * @param bufferSize Buffer size, must be at least 4 bytes. Exactly 4 bytes are written. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_UltralightWrite(uint8_t page, uint8_t *buffer, uint8_t bufferSize); + + /** + * MIFARE Decrement subtracts the delta from the value of the addressed block, and stores the result in a volatile memory. + * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. + * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. + * Use MIFARE_Transfer() to store the result in a block. + * + * @param blockAddr The block (0-0xff) number. + * @param delta This number is subtracted from the value of block blockAddr. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_Decrement (uint8_t blockAddr, uint32_t delta); + + /** + * MIFARE Increment adds the delta to the value of the addressed block, and stores the result in a volatile memory. + * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. + * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. + * Use MIFARE_Transfer() to store the result in a block. + * + * @param blockAddr The block (0-0xff) number. + * @param delta This number is added to the value of block blockAddr. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_Increment (uint8_t blockAddr, uint32_t delta); + + /** + * MIFARE Restore copies the value of the addressed block into a volatile memory. + * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. + * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. + * Use MIFARE_Transfer() to store the result in a block. + * + * @param blockAddr The block (0-0xff) number. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_Restore (uint8_t blockAddr); + + /** + * MIFARE Transfer writes the value stored in the volatile memory into one MIFARE Classic block. + * For MIFARE Classic only. The sector containing the block must be authenticated before calling this function. + * Only for blocks in "value block" mode, ie with access bits [C1 C2 C3] = [110] or [001]. + * + * @param blockAddr The block (0-0xff) number. + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_Transfer (uint8_t blockAddr); + + // ************************************************************************************ + //@} + + + // ************************************************************************************ + //! @name Support functions + // ************************************************************************************ + //@{ + + /** + * Wrapper for MIFARE protocol communication. + * Adds CRC_A, executes the Transceive command and checks that the response is MF_ACK or a timeout. + * + * @param sendData Pointer to the data to transfer to the FIFO. Do NOT include the CRC_A. + * @param sendLen Number of bytes in sendData. + * @param acceptTimeout True => A timeout is also success + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t PCD_MIFARE_Transceive(uint8_t *sendData, uint8_t sendLen, bool acceptTimeout = false); + + /** + * Translates the SAK (Select Acknowledge) to a PICC type. + * + * @param sak The SAK byte returned from PICC_Select(). + * + * @return PICC_Type + */ + uint8_t PICC_GetType (uint8_t sak); + + /** + * Returns a string pointer to the PICC type name. + * + * @param type One of the PICC_Type enums. + * + * @return A string pointer to the PICC type name. + */ + char* PICC_GetTypeName (uint8_t type); + + /** + * Returns a string pointer to a status code name. + * + * @param code One of the StatusCode enums. + * + * @return A string pointer to a status code name. + */ + char* GetStatusCodeName (uint8_t code); + + /** + * Calculates the bit pattern needed for the specified access bits. In the [C1 C2 C3] tupples C1 is MSB (=4) and C3 is LSB (=1). + * + * @param accessBitBuffer Pointer to byte 6, 7 and 8 in the sector trailer. Bytes [0..2] will be set. + * @param g0 Access bits [C1 C2 C3] for block 0 (for sectors 0-31) or blocks 0-4 (for sectors 32-39) + * @param g1 Access bits [C1 C2 C3] for block 1 (for sectors 0-31) or blocks 5-9 (for sectors 32-39) + * @param g2 Access bits [C1 C2 C3] for block 2 (for sectors 0-31) or blocks 10-14 (for sectors 32-39) + * @param g3 Access bits [C1 C2 C3] for the sector trailer, block 3 (for sectors 0-31) or block 15 (for sectors 32-39) + */ + void MIFARE_SetAccessBits (uint8_t *accessBitBuffer, + uint8_t g0, + uint8_t g1, + uint8_t g2, + uint8_t g3); + + // ************************************************************************************ + //@} + + + // ************************************************************************************ + //! @name Convenience functions - does not add extra functionality + // ************************************************************************************ + //@{ + + /** + * Returns true if a PICC responds to PICC_CMD_REQA. + * Only "new" cards in state IDLE are invited. Sleeping cards in state HALT are ignored. + * + * @return bool + */ + bool PICC_IsNewCardPresent(void); + + /** + * Simple wrapper around PICC_Select. + * Returns true if a UID could be read. + * Remember to call PICC_IsNewCardPresent(), PICC_RequestA() or PICC_WakeupA() first. + * The read UID is available in the class variable uid. + * + * @return bool + */ + bool PICC_ReadCardSerial (void); + + // ************************************************************************************ + //@} + + +private: + SPI m_SPI; + DigitalOut m_CS; + DigitalOut m_RESET; + + /** + * Helper function for the two-step MIFARE Classic protocol operations Decrement, Increment and Restore. + * + * @param command The command to use + * @param blockAddr The block (0-0xff) number. + * @param data The data to transfer in step 2 + * + * @return STATUS_OK on success, STATUS_??? otherwise. + */ + uint8_t MIFARE_TwoStepHelper(uint8_t command, uint8_t blockAddr, uint32_t data); +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MPU6050.lib Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,1 @@ +https://developer.mbed.org/users/OsmanKameric/code/MPU6050/#1e0b279766be
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MotionFSM/Fsm.cpp Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,45 @@ +#include <Moving.h> +#include <Stacionary.h> +#include <Fsm.h> + +FsmStates::FsmStates() : movingState_(new Moving(*this,timer)), + stacionaryState_(new Stacionary(*this,timer)) +{ + currentState(stacionaryState()); +} + + + +State* FsmStates::stacionaryState() +{ + return stacionaryState_; +} + +State* FsmStates::movingState() +{ + return movingState_; +} + +State* FsmStates::currentState() +{ + return currentState_; +} +void FsmStates::currentState(State* state) +{ + currentState_ = state; +} + +FsmStates::~FsmStates() +{ + delete stacionaryState_; + delete movingState_; +} + +Fsm::Fsm() : states_() +{ + + +} + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MotionFSM/Moving.cpp Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,14 @@ +#include <Moving.h> +#include <Events.h> +#include <Fsm.h> + +Moving::Moving(FsmStates& states, Timer& timer): State(states,timer) {} + +State* Moving::handle(Stop& event) +{ + printf("Odoh u ********************************** STACIONARY STATE\r\n"); + return states_.stacionaryState(); +} + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MotionFSM/Stacionary.cpp Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,13 @@ +#include <Stacionary.h> +#include <Events.h> +#include <Fsm.h> + +Stacionary::Stacionary(FsmStates& states, Timer& timer): State(states, timer) {} + +State* Stacionary::handle(Move& event) +{ + printf("Odoh u ********************************** MOVING STATE\r\n"); + return states_.movingState(); +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MotionFSM/State.cpp Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,9 @@ +#include <Fsm.h> +#include <State.h> + +State::State(FsmStates& states,Timer& timer): states_(states),stateTimer_(timer){} + +State* State::handle(Stop& event) { return states_.currentState(); } +State* State::handle(Move& event) { return states_.currentState(); } + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MotionFSM/include/Events.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,7 @@ +#ifndef MOTIONFSM_EVENTS_H_ +#define MOTIONFSM_EVENTS_H_ + +struct Stop {}; +struct Move {}; + +#endif /* ifndef MOTIONFSM_EVENTS_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MotionFSM/include/Fsm.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,48 @@ +#ifndef MOTIONFSM_FSM_H_ +#define MOTIONFSM_FSM_H_ +#include <State.h> +#include "mbed.h" + +#include <Events.h> + +struct Stop; +struct Move; + +class FsmStates { + public: + FsmStates(); + + State* movingState(); + State* stacionaryState(); + State* currentState(); + + void currentState(State* state); + + ~FsmStates(); + + private: + + State* movingState_; + State* stacionaryState_; + State* currentState_; + + Timer timer; + +}; + +class Fsm { + public: + Fsm(); + template <typename Event> + void handle(Event& event){ + State* state = states_.currentState()->handle(event); + states_.currentState(state); + } + + virtual ~Fsm() {} + FsmStates states_; + private: + + +}; +#endif /* ifndef MOTIONFSM_FSM_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MotionFSM/include/Moving.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,17 @@ +#ifndef FSM_MOVING_H_ +#define FSM_MOVING_H_ + +#include <State.h> +struct Stop; +class FsmStates; + +class Moving : public State { + public: + Moving(FsmStates& states, Timer& timer); + State* handle(Stop& event); + + private: + unsigned timeForLongPress_; +}; + +#endif /* ifndef FSM_CONNECTED_TRANSIOTION_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MotionFSM/include/Stacionary.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,15 @@ +#ifndef FSM_STACIONARY_H_ +#define FSM_STACIONARY_H_ + +#include <State.h> +#include "mbed.h" + +struct Move; +class FsmStates; + +class Stacionary : public State { + public: + Stacionary(FsmStates& states, Timer& timer); + State* handle(Move& event); +}; +#endif /* ifndef FSM_DISCONNECTED_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MotionFSM/include/State.h Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,20 @@ +#ifndef FSM_STATE_H_ +#define FSM_STATE_H_ +#include "mbed.h" +struct Stop; +struct Move; + +class FsmStates; + +class State { + public: + State(FsmStates& state, Timer& timer); + virtual State* handle(Stop& event); + virtual State* handle(Move& event); + virtual ~State() {} + + protected: + FsmStates& states_; + Timer& stateTimer_; +}; +#endif /* ifndef FSM_STATE_H_ */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/PinDetect.lib Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,1 @@ +https://mbed.org/users/AjK/code/PinDetect/#cb3afc45028b
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.md Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,87 @@ +# Getting started with Blinky on mbed OS + +This guide reviews the steps required to get Blinky working on an mbed OS platform. + +Please install [mbed CLI](https://github.com/ARMmbed/mbed-cli#installing-mbed-cli). + +## Import the example application + +From the command-line, import the example: + +``` +mbed import mbed-os-example-blinky +cd mbed-os-example-blinky +``` + +### Now compile + +Invoke `mbed compile`, and specify the name of your platform and your favorite toolchain (`GCC_ARM`, `ARM`, `IAR`). For example, for the ARM Compiler 5: + +``` +mbed compile -m K64F -t ARM +``` + +Your PC may take a few minutes to compile your code. At the end, you see the following result: + +``` +[snip] ++----------------------------+-------+-------+------+ +| Module | .text | .data | .bss | ++----------------------------+-------+-------+------+ +| Misc | 13939 | 24 | 1372 | +| core/hal | 16993 | 96 | 296 | +| core/rtos | 7384 | 92 | 4204 | +| features/FEATURE_IPV4 | 80 | 0 | 176 | +| frameworks/greentea-client | 1830 | 60 | 44 | +| frameworks/utest | 2392 | 512 | 292 | +| Subtotals | 42618 | 784 | 6384 | ++----------------------------+-------+-------+------+ +Allocated Heap: unknown +Allocated Stack: unknown +Total Static RAM memory (data + bss): 7168 bytes +Total RAM memory (data + bss + heap + stack): 7168 bytes +Total Flash memory (text + data + misc): 43402 bytes +Image: .\.build\K64F\ARM\mbed-os-example-blinky.bin +``` + +### Program your board + +1. Connect your mbed device to the computer over USB. +1. Copy the binary file to the mbed device. +1. Press the reset button to start the program. + +The LED on your platform turns on and off. + +## Export the project to Keil MDK, and debug your application + +From the command-line, run the following command: + +``` +mbed export -m K64F -i uvision +``` + +To debug the application: + +1. Start uVision. +1. Import the uVision project generated earlier. +1. Compile your application, and generate an `.axf` file. +1. Make sure uVision is configured to debug over CMSIS-DAP (From the Project menu > Options for Target '...' > Debug tab > Use CMSIS-DAP Debugger). +1. Set breakpoints, and start a debug session. + +![Image of uVision](img/uvision.png) + +## Troubleshooting + +1. Make sure `mbed-cli` is working correctly and its version is `>1.0.0` + + ``` + mbed --version + ``` + + If not, you can update it: + + ``` + pip install mbed-cli --upgrade + ``` + +2. If using Keil MDK, make sure you have a license installed. [MDK-Lite](http://www.keil.com/arm/mdk.asp) has a 32 KB restriction on code size. \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/circular_buffer.lib Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,1 @@ +https://mbed.org/users/hamparawa/code/circular_buffer/#b241b75b052b
Binary file img/uvision.png has changed
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,149 @@ +#include "mbed.h" +#include "MPU6050.h" +#include "I2Cdev.h" +#include <Fsm.h> +#include <CaseFsm.h> +#include <CaseEvents.h> +#include <Events.h> +#include "log.h" +#include "DataLogger.h" + +//#include "circular_buffer.h" +#include "MFRC522.h" +#include "PinDetect.h" + + +#define CURRENT_TIME 1504029000 + +#define SPI_MOSI PA_7 +#define SPI_MISO PA_6 +#define SPI_SCK PA_5 +#define SPI_CS PB_6 +#define MF_RESET PB_3 + + + + + +struct CaseFsmLog { + int caseState; + uint32_t timeStamp; +}; + +CaseFsmLog caseFsmLog; +CaseFsm* caseFsm; +struct SwitchPosition switchPosition; + +DigitalOut led1(LED1); +Serial pc(USBTX,USBRX); +struct RFIDEvent rfidEvent; +struct TimerEnd timerEnd; +/* +struct MotionLog { + int motX; + int motY; + int motZ; + uint32_t timeStamp; + uint8_t motionByte; +}; + +struct MotionFsmLog { + int motionState; + uint32_t timeStamp; +}; +MotionLog motionLog; +MotionFsmLog motionFsmLog; + + +circular_buffer<MotionLog> cb(20); +circular_buffer<MotionFsmLog> mfl(20); +circular_buffer<CaseFsmLog> cfl(20); +MPU6050 mpu; +bool zero_detect; +Fsm* motionFsm; + + + + +bool XnegMD, XposMD, YnegMD, YposMD, ZnegMD, ZposMD; +int8_t threshold; + +float temp; +bool test=0; +void flip() +{ + test=1; +} + + + + +struct Move move; +struct Stop stop; + + + +*/ + +InterruptIn button1(D7); +//PinDetect button1(PA_9); +InterruptIn button2(D8); +InterruptIn button3(D9); +//InterruptIn button4(PA_7); + +//InterruptIn mpuInterrupt(PA_10); +bool flag = false; +int flag_switch=0; +int flag_rfid_Event=0; +int flag_timerend=0; +bool DeviceIsFull = false; +void button1PressedCallback() +{ + flag_switch=1; + caseFsm->handle(switchPosition); +} + +void button2PressedCallback() +{ + flag_rfid_Event=1; + caseFsm->handle(rfidEvent); + +} +void button3PressedCallback() +{ + flag_timerend=1; + caseFsm->handle(timerEnd); +} + + + + Log mojlog; + DataLogger <Log> mojlogger; + mojlogger.print(); + mojlogger.savelog(mojlog); + mojlogger.print(); + + + + flagswitch=0; + flag_rfid_Event=0; + flag_timerend=0; + + if(flagswitch==1){ + + if(caseFsm->DeviceInFullState()) { + pc.printf("Waiting 5 seconds for RFID event...\r\n"); + while (caseFsm->DeviceInFullState()) { + // Look for new cards + + + + } + + } + } + + + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os.lib Tue Nov 07 16:35:14 2017 +0000 @@ -0,0 +1,1 @@ +https://github.com/ARMmbed/mbed-os/#c9e63f14085f5751ff5ead79a7c0382d50a813a2