Skip to content

Commit

Permalink
Added features #7 , #5, #4
Browse files Browse the repository at this point in the history
Made a better readerWriter example and included some of the enhancements in the issue list
  • Loading branch information
Strooom committed Jan 22, 2020
1 parent d79b242 commit 2d47ac4
Show file tree
Hide file tree
Showing 8 changed files with 391 additions and 167 deletions.
162 changes: 116 additions & 46 deletions src/NCI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,25 +11,20 @@

//#include "logging.h" // Toolkit to allow easy logging towards, eg. Serial UART
//#include "NciToolkit.h"


#include "NCI.h"
#include "NFCReaderWriter.h"


NCI::NCI(PN7150Interface &theHardwareInterface) : theHardwareInterface(theHardwareInterface), theState(NciState::HwResetRfc)
NCI::NCI(PN7150Interface &aHardwareInterface) : theHardwareInterface(aHardwareInterface), theState(NciState::HwResetRfc), theTagsStatus(TagsPresentStatus::unknown)
{
}

void NCI::initialize()
{
theHardwareInterface.initialize();
theState = NciState::HwResetRfc;
}

void NCI::registrate(NFCReaderWriter *aReaderWriter)
{
theReaderWriter = aReaderWriter;
theState = NciState::HwResetRfc; // re-initializing the state, so we can re-initialize at anytime
theTagsStatus = TagsPresentStatus::unknown;
nmbrOfTags = 0;
}

void NCI::run()
Expand Down Expand Up @@ -70,9 +65,9 @@ void NCI::run()

case NciState::SwResetRfc:
{
sendMessage(MsgTypeCommand, GroupIdCore, CORE_INIT_CMD); // CORE_INIT-CMD
setTimeOut(10); // we should get a RESPONSE within 10 ms, typically it takes 0.5ms
theState = NciState::SwResetWfr; // move to next state, waiting for response
sendMessage(MsgTypeCommand, GroupIdCore, CORE_INIT_CMD); // CORE_INIT-CMD
setTimeOut(10); // we should get a RESPONSE within 10 ms, typically it takes 0.5ms
theState = NciState::SwResetWfr; // move to next state, waiting for response
}
break;

Expand All @@ -93,14 +88,14 @@ void NCI::run()
}
else if (isTimeOut())
{
theState = NciState::Error; // time out waiting for response..
theState = NciState::Error; // time out waiting for response..
}
break;

case NciState::EnableCustomCommandsRfc:
sendMessage(MsgTypeCommand, GroupIdProprietary, NCI_PROPRIETARY_ACT_CMD); // Send NCI_PROPRIETARY_ACT_CMD to activate extra PN7150-NCI features
setTimeOut(10); // we should get a RESPONSE within 10 ms, typically it takes 0.5ms
theState = NciState::EnableCustomCommandsWfr; // move to next state, waiting for response
sendMessage(MsgTypeCommand, GroupIdProprietary, NCI_PROPRIETARY_ACT_CMD); // Send NCI_PROPRIETARY_ACT_CMD to activate extra PN7150-NCI features
setTimeOut(10); // we should get a RESPONSE within 10 ms, typically it takes 0.5ms
theState = NciState::EnableCustomCommandsWfr; // move to next state, waiting for response
break;

case NciState::EnableCustomCommandsWfr:
Expand All @@ -126,15 +121,8 @@ void NCI::run()
break;

case NciState::RfIdleCmd:
// After configuring, we instruct the NFCDevice to go into Poll mode..
{
uint8_t payloadData[] = { 3, NFC_A_PASSIVE_POLL_MODE, 0x01, NFC_B_PASSIVE_POLL_MODE, 0x01, NFC_F_PASSIVE_POLL_MODE, 0x01 };
// TODO : instead of setting a fixed scanning for these 3 types, we should request the to be scanned for types from the ReaderWriter configuration...
sendMessage(MsgTypeCommand, GroupIdRfManagement, RF_DISCOVER_CMD, payloadData, 7); //
setTimeOut(10); // we should get a RESPONSE within 10 ms
theState = NciState::RfIdleWfr; // move to next state, waiting for Response
}
break;
// After configuring, we are ready to go into Discovery, but we wait for the readerWriter application to give us this trigger
break;

case NciState::RfIdleWfr:
if (theHardwareInterface.hasMessage())
Expand All @@ -143,18 +131,19 @@ void NCI::run()
bool isOk = (4 == rxMessageLength); // Does the received Msg have the correct lenght ?
isOk = isOk && isMessageType(MsgTypeResponse, GroupIdRfManagement, RF_DISCOVER_RSP); // Is the received Msg the correct type ?
isOk = isOk && (STATUS_OK == rxBuffer[3]); // Is the received Status code Status_OK ?
if (isOk) // if everything is OK...
if (isOk) // if everything is OK...
{
theState = NciState::RfDiscovery; // ...move to the next state
theState = NciState::RfDiscovery; // ...move to the next state
setTimeOut(500); // set a timeout of 1 second. If it times out, it means no cards are present..
}
else // if not..
else // if not..
{
theState = NciState::Error; // .. goto error state
theState = NciState::Error; // .. goto error state
}
}
else if (isTimeOut())
{
theState = NciState::Error; // time out waiting for response..
theState = NciState::Error; // time out waiting for response..
}
break;

Expand All @@ -167,20 +156,26 @@ void NCI::run()
if (isMessageType(MsgTypeNotification, GroupIdRfManagement, RF_INTF_ACTIVATED_NTF))
{
// When a single tag/card is detected, the PN7150 will immediately activate it and send you this type of notification
theReaderWriter->reportTagProperties(rxBuffer, RF_INTF_ACTIVATED_NTF); // report the properties of this tag to the readerWriter application
saveTag(RF_INTF_ACTIVATED_NTF); // save properties of this Tag in the Tags array
theTagsStatus = TagsPresentStatus::singleTagPresent;
theState = NciState::RfPollActive; // move to PollActive, and wait there for further commands..

}
else if (isMessageType(MsgTypeNotification, GroupIdRfManagement, RF_DISCOVER_NTF))
{
// When multiple tags/cards are detected, the PN7150 will notify them all and wait for the DH to select one
// The first card will have NotificationType == 2 and move the stateMachine to WaitForAllDiscoveries.
// More notifications will come in that state
theReaderWriter->reportTagProperties(rxBuffer, RF_DISCOVER_NTF); // report the properties of this tag to the readerWriter application
setTimeOut(10); // we should get more Notifications, so set a timeout so we don't wait forever
saveTag(RF_DISCOVER_NTF); // save properties of this Tag in the Tags array
setTimeOut(25); // we should get more Notifications ubt set a timeout so we don't wait forever
theTagsStatus = TagsPresentStatus::multipleTagsPresent;
theState = NciState::RfWaitForAllDiscoveries;
}
}
else if (isTimeOut())
{
theTagsStatus = TagsPresentStatus::noTagsPresent; // this means no card has been detected for xxx millisecond, so we can conclude that no cards are present
}

break;

case NciState::RfWaitForAllDiscoveries:
Expand All @@ -194,12 +189,13 @@ void NCI::run()
{
case notificationType::lastNotification:
case notificationType::lastNotificationNfccLimit:
theReaderWriter->reportTagProperties(rxBuffer, RF_DISCOVER_NTF); // report the properties of this tag to the readerWriter application
saveTag(RF_DISCOVER_NTF); // save properties of this Tag in the Tags array
theState = NciState::RfWaitForHostSelect;
break;

case notificationType::moreNotification:
theReaderWriter->reportTagProperties(rxBuffer, RF_DISCOVER_NTF); // report the properties of this tag to the readerWriter application
setTimeOut(25); // we should get more Notifications, so set a timeout so we don't wait forever
saveTag(RF_DISCOVER_NTF); // save properties of this Tag in the Tags array
break;

default:
Expand Down Expand Up @@ -286,9 +282,26 @@ void NCI::run()
}
}

void NCI::activate()
{
NciState tmpState = getState();
if (tmpState == NciState::RfIdleCmd)
{
uint8_t payloadData[] = { 4, NFC_A_PASSIVE_POLL_MODE, 0x01, NFC_B_PASSIVE_POLL_MODE, 0x01, NFC_F_PASSIVE_POLL_MODE, 0x01, NFC_15693_PASSIVE_POLL_MODE, 0x01 };
// TODO : instead of setting a fixed scanning for these 4 types, we should pass the to be scanned for types as parameters from the ReaderWriter... https://github.com/Strooom/PN7150/issues/1
sendMessage(MsgTypeCommand, GroupIdRfManagement, RF_DISCOVER_CMD, payloadData, 9); //
setTimeOut(10); // we should get a RESPONSE within 10 ms
theState = NciState::RfIdleWfr; // move to next state, waiting for Response
}
else
{
// Error : we can only activate polling when in Idle...
}
}

void NCI::deActivate(NciRfDeAcivationMode theMode)
{
// TODO : investigate how the different types of deactivation should behave
nmbrOfTags = 0;
NciState tmpState = getState();
switch (tmpState)
{
Expand All @@ -297,6 +310,7 @@ void NCI::deActivate(NciRfDeAcivationMode theMode)
uint8_t payloadData[] = { (uint8_t)NciRfDeAcivationMode::IdleMode }; // in RfWaitForHostSelect, the deactivation type is ignored by the NFCC
sendMessage(MsgTypeCommand, GroupIdRfManagement, RF_DEACTIVATE_CMD, payloadData, 1); //
setTimeOut(10); // we should get a RESPONSE within 10 ms
theTagsStatus = TagsPresentStatus::unknown;
theState = NciState::RfDeActivate1Wfr; // move to next state, waiting for response
}
break;
Expand All @@ -306,6 +320,7 @@ void NCI::deActivate(NciRfDeAcivationMode theMode)
uint8_t payloadData[] = { (uint8_t)theMode };
sendMessage(MsgTypeCommand, GroupIdRfManagement, RF_DEACTIVATE_CMD, payloadData, 1); //
setTimeOut(10); // we should get a RESPONSE within 10 ms
theTagsStatus = TagsPresentStatus::unknown;
theState = NciState::RfDeActivate2Wfr; // move to next state, waiting for response
}
break;
Expand All @@ -315,42 +330,57 @@ void NCI::deActivate(NciRfDeAcivationMode theMode)
}
}

NciState NCI::getState()
NciState NCI::getState() const
{
return theState;
}

TagsPresentStatus NCI::getTagsPresentStatus() const
{
return theTagsStatus;
}

uint8_t NCI::getNmbrOfTags() const
{
return nmbrOfTags;
}

Tag* NCI::getTag(uint8_t index)
{
return &theTags[index];
}

void NCI::sendMessage(uint8_t messageType, uint8_t groupId, uint8_t opcodeId)
{
txBuffer[0] = (messageType | groupId) & 0xEF; // put messageType and groupId in first byte, Packet Boundary Flag is always 0
txBuffer[1] = opcodeId & 0x3F; // put opcodeId in second byte, clear Reserved for Future Use (RFU) bits
txBuffer[2] = 0x00; // payloadLength goes in third byte
theHardwareInterface.write(txBuffer, 3);
(void) theHardwareInterface.write(txBuffer, 3); // TODO : could make this more robust by checking the return value and go into error is write did not succees
}

void NCI::sendMessage(uint8_t messageType, uint8_t groupId, uint8_t opcodeId, uint8_t payloadData[], uint8_t payloadLength)
{
txBuffer[0] = (messageType | groupId) & 0xEF; // put messageType and groupId in first byte, Packet Boundary Flag is always 0
txBuffer[1] = opcodeId & 0x3F; // put opcodeId in second byte, clear Reserved for Future Use (RFU) bits
txBuffer[2] = payloadLength; // payloadLength goes in third byte
for (uint32_t index = 0; index < payloadLength; index++) // copy the payload
txBuffer[0] = (messageType | groupId) & 0xEF; // put messageType and groupId in first byte, Packet Boundary Flag is always 0
txBuffer[1] = opcodeId & 0x3F; // put opcodeId in second byte, clear Reserved for Future Use (RFU) bits
txBuffer[2] = payloadLength; // payloadLength goes in third byte
for (uint32_t index = 0; index < payloadLength; index++) // copy the payload
{
txBuffer[index + 3] = payloadData[index];
}
theHardwareInterface.write(txBuffer, 3 + payloadLength);
(void) theHardwareInterface.write(txBuffer, 3 + payloadLength); // TODO : could make this more robust by checking the return value and go into error is write did not succees
}

void NCI::getMessage()
{
rxMessageLength = theHardwareInterface.read(rxBuffer);
}

bool NCI::isMessageType(uint8_t messageType, uint8_t groupId, uint8_t opcodeId)
bool NCI::isMessageType(uint8_t messageType, uint8_t groupId, uint8_t opcodeId) const
{
return (((messageType | groupId) & 0xEF) == rxBuffer[0]) && ((opcodeId & 0x3F) == rxBuffer[1]);
}

bool NCI::isTimeOut()
bool NCI::isTimeOut() const
{
return ((millis() - timeOutStartTime) >= timeOut);
}
Expand All @@ -361,3 +391,43 @@ void NCI::setTimeOut(unsigned long theTimeOut)
timeOut = theTimeOut;
}

void NCI::saveTag(uint8_t msgType)
{
// Store the properties of detected TAGs in the Tag array.
// Tag info can come in two different NCI messages : RF_DISCOVER_NTF and RF_INTF_ACTIVATED_NTF and the Tag properties are in slightly different location inside these messages

if (nmbrOfTags < maxNmbrTags)
{
uint8_t offSet; // Offset in the NCI message where we can find the UniqueID
switch (msgType)
{
case RF_INTF_ACTIVATED_NTF:
offSet = 12;
break;

case RF_DISCOVER_NTF:
offSet = 9;
break;

default:
return; // unknown type of msg sent here ?? we just ignore it..
break;
}

uint8_t NfcId1Length = rxBuffer[offSet];
if (NfcId1Length > 10)
{
NfcId1Length = 10; // limit the length to 10, so in case of whatever error we don't write beyond the boundaries of the array
}
uint8_t newTagIndex = nmbrOfTags; // index to the array item where we will store the info

theTags[newTagIndex].uniqueIdLength = NfcId1Length; // copy the length of the unique ID, is 4, 7 or 10
for (uint8_t index = 0; index < NfcId1Length; index++) // copy all bytes of the unique ID
{
theTags[newTagIndex].uniqueId[index] = rxBuffer[offSet + 1 + index];
}
theTags[newTagIndex].detectionTimestamp = millis();

nmbrOfTags++; // one more tag in the array now
}
}
Loading

0 comments on commit 2d47ac4

Please sign in to comment.