mirror of https://github.com/arendst/Tasmota.git
PN532: Add Read/Write Data support
This commit is contained in:
parent
4224f25234
commit
549080b850
|
@ -322,7 +322,8 @@
|
||||||
// #define USE_DS3231 // Enable DS3231 external RTC in case no Wifi is avaliable. See docs in the source file (+1k2 code)
|
// #define USE_DS3231 // Enable DS3231 external RTC in case no Wifi is avaliable. See docs in the source file (+1k2 code)
|
||||||
// #define USE_RTC_ADDR 0x68 // Default I2C address 0x68
|
// #define USE_RTC_ADDR 0x68 // Default I2C address 0x68
|
||||||
// #define USE_MGC3130 // Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem)
|
// #define USE_MGC3130 // Enable MGC3130 Electric Field Effect Sensor (I2C address 0x42) (+2k7 code, 0k3 mem)
|
||||||
// #define USE_PN532_I2C // Enable PN532 - Near Field Communication (NFC) controller (+1k6 code)
|
// #define USE_PN532_I2C // Enable PN532 - Near Field Communication (NFC) controller (+3k3 code, 508 bytes of mem)
|
||||||
|
// #define USE_PN532_CAUSE_EVENTS // Enable PN532 driver to cause event's on card read in addition to immediate telemetry
|
||||||
|
|
||||||
// #define USE_DISPLAY // Add I2C Display Support (+2k code)
|
// #define USE_DISPLAY // Add I2C Display Support (+2k code)
|
||||||
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
|
#define USE_DISPLAY_MODES1TO5 // Enable display mode 1 to 5 in addition to mode 0
|
||||||
|
|
|
@ -34,8 +34,14 @@
|
||||||
|
|
||||||
#define PN532_COMMAND_GETFIRMWAREVERSION 0x02
|
#define PN532_COMMAND_GETFIRMWAREVERSION 0x02
|
||||||
#define PN532_COMMAND_SAMCONFIGURATION 0x14
|
#define PN532_COMMAND_SAMCONFIGURATION 0x14
|
||||||
|
#define PN532_COMMAND_INDATAEXCHANGE 0x40
|
||||||
#define PN532_COMMAND_INLISTPASSIVETARGET 0x4A
|
#define PN532_COMMAND_INLISTPASSIVETARGET 0x4A
|
||||||
|
|
||||||
|
#define MIFARE_CMD_READ 0x30
|
||||||
|
#define MIFARE_CMD_AUTH_A 0x60
|
||||||
|
#define MIFARE_CMD_AUTH_B 0x61
|
||||||
|
#define MIFARE_CMD_WRITE 0xA0
|
||||||
|
|
||||||
#define PN532_PREAMBLE 0x00
|
#define PN532_PREAMBLE 0x00
|
||||||
#define PN532_STARTCODE1 0x00
|
#define PN532_STARTCODE1 0x00
|
||||||
#define PN532_STARTCODE2 0xFF
|
#define PN532_STARTCODE2 0xFF
|
||||||
|
@ -56,6 +62,8 @@ uint8_t pn532_i2c_packetbuffer[64];
|
||||||
uint8_t pn532_i2c_scan_defer_report = 0; // If a valid card was found we will not scan for one again in the same two seconds so we set this to 19 if a card was found
|
uint8_t pn532_i2c_scan_defer_report = 0; // If a valid card was found we will not scan for one again in the same two seconds so we set this to 19 if a card was found
|
||||||
uint8_t pn532_i2c_command = 0;
|
uint8_t pn532_i2c_command = 0;
|
||||||
uint8_t pn532_i2c_disable = 0;
|
uint8_t pn532_i2c_disable = 0;
|
||||||
|
uint8_t pn532_i2c_function = 0;
|
||||||
|
uint8_t pn532_i2c_newdata[16];
|
||||||
|
|
||||||
const uint8_t PROGMEM pn532_global_timeout = 10;
|
const uint8_t PROGMEM pn532_global_timeout = 10;
|
||||||
|
|
||||||
|
@ -227,8 +235,8 @@ bool PN532_SAMConfig(void)
|
||||||
{
|
{
|
||||||
pn532_i2c_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION;
|
pn532_i2c_packetbuffer[0] = PN532_COMMAND_SAMCONFIGURATION;
|
||||||
pn532_i2c_packetbuffer[1] = 0x01; // normal mode;
|
pn532_i2c_packetbuffer[1] = 0x01; // normal mode;
|
||||||
pn532_i2c_packetbuffer[2] = 0x14; // timeout 50ms * 20 = 1 second
|
pn532_i2c_packetbuffer[2] = 0x01; // timeout 50ms * 1 = 50ms
|
||||||
pn532_i2c_packetbuffer[3] = 0x01; // use IRQ pin!
|
pn532_i2c_packetbuffer[3] = 0x01; // Disable IRQ pin
|
||||||
|
|
||||||
if (PN532_writeCommand(pn532_i2c_packetbuffer, 4))
|
if (PN532_writeCommand(pn532_i2c_packetbuffer, 4))
|
||||||
return false;
|
return false;
|
||||||
|
@ -277,26 +285,170 @@ boolean PN532_readPassiveTargetID(uint8_t cardbaudrate, uint8_t *uid, uint8_t *u
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t mifareclassic_AuthenticateBlock (uint8_t *uid, uint8_t uidLen, uint32_t blockNumber, uint8_t keyNumber, uint8_t *keyData)
|
||||||
|
{
|
||||||
|
uint8_t i;
|
||||||
|
uint8_t _key[6];
|
||||||
|
uint8_t _uid[7];
|
||||||
|
uint8_t _uidLen;
|
||||||
|
|
||||||
|
// Hang on to the key and uid data
|
||||||
|
memcpy (_key, keyData, 6);
|
||||||
|
memcpy (_uid, uid, uidLen);
|
||||||
|
_uidLen = uidLen;
|
||||||
|
|
||||||
|
// Prepare the authentication command //
|
||||||
|
pn532_i2c_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE; /* Data Exchange Header */
|
||||||
|
pn532_i2c_packetbuffer[1] = 1; /* Max card numbers */
|
||||||
|
pn532_i2c_packetbuffer[2] = (keyNumber) ? MIFARE_CMD_AUTH_B : MIFARE_CMD_AUTH_A;
|
||||||
|
pn532_i2c_packetbuffer[3] = blockNumber; /* Block Number (1K = 0..63, 4K = 0..255 */
|
||||||
|
memcpy (&pn532_i2c_packetbuffer[4], _key, 6);
|
||||||
|
for (i = 0; i < _uidLen; i++) {
|
||||||
|
pn532_i2c_packetbuffer[10 + i] = _uid[i]; /* 4 bytes card ID */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PN532_writeCommand(pn532_i2c_packetbuffer, 10 + _uidLen))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Read the response packet
|
||||||
|
PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer));
|
||||||
|
|
||||||
|
// Check if the response is valid and we are authenticated???
|
||||||
|
// for an auth success it should be bytes 5-7: 0xD5 0x41 0x00
|
||||||
|
// Mifare auth error is technically byte 7: 0x14 but anything other and 0x00 is not good
|
||||||
|
if (pn532_i2c_packetbuffer[0] != 0x00) {
|
||||||
|
// Authentification failed
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t mifareclassic_ReadDataBlock (uint8_t blockNumber, uint8_t *data)
|
||||||
|
{
|
||||||
|
/* Prepare the command */
|
||||||
|
pn532_i2c_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
|
||||||
|
pn532_i2c_packetbuffer[1] = 1; /* Card number */
|
||||||
|
pn532_i2c_packetbuffer[2] = MIFARE_CMD_READ; /* Mifare Read command = 0x30 */
|
||||||
|
pn532_i2c_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
|
||||||
|
|
||||||
|
/* Send the command */
|
||||||
|
if (PN532_writeCommand(pn532_i2c_packetbuffer, 4)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the response packet */
|
||||||
|
PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer));
|
||||||
|
|
||||||
|
/* If byte 8 isn't 0x00 we probably have an error */
|
||||||
|
if (pn532_i2c_packetbuffer[0] != 0x00) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy the 16 data bytes to the output buffer */
|
||||||
|
/* Block content starts at byte 9 of a valid response */
|
||||||
|
memcpy (data, &pn532_i2c_packetbuffer[1], 16);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t mifareclassic_WriteDataBlock (uint8_t blockNumber, uint8_t *data)
|
||||||
|
{
|
||||||
|
/* Prepare the first command */
|
||||||
|
pn532_i2c_packetbuffer[0] = PN532_COMMAND_INDATAEXCHANGE;
|
||||||
|
pn532_i2c_packetbuffer[1] = 1; /* Card number */
|
||||||
|
pn532_i2c_packetbuffer[2] = MIFARE_CMD_WRITE; /* Mifare Write command = 0xA0 */
|
||||||
|
pn532_i2c_packetbuffer[3] = blockNumber; /* Block Number (0..63 for 1K, 0..255 for 4K) */
|
||||||
|
memcpy(&pn532_i2c_packetbuffer[4], data, 16); /* Data Payload */
|
||||||
|
|
||||||
|
/* Send the command */
|
||||||
|
if (PN532_writeCommand(pn532_i2c_packetbuffer, 20)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the response packet */
|
||||||
|
return (0 < PN532_readResponse(pn532_i2c_packetbuffer, sizeof(pn532_i2c_packetbuffer)));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PN532_ScanForTag(void)
|
void PN532_ScanForTag(void)
|
||||||
{
|
{
|
||||||
if (pn532_i2c_disable) { return; }
|
if (pn532_i2c_disable) { return; }
|
||||||
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
|
uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 };
|
||||||
uint8_t uid_len = 0;
|
uint8_t uid_len = 0;
|
||||||
|
uint8_t card_data[16];
|
||||||
|
boolean erase_success = false;
|
||||||
|
boolean set_success = false;
|
||||||
if (PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uid_len)) {
|
if (PN532_readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uid_len)) {
|
||||||
if (pn532_i2c_scan_defer_report > 0) {
|
if (pn532_i2c_scan_defer_report > 0) {
|
||||||
pn532_i2c_scan_defer_report--;
|
pn532_i2c_scan_defer_report--;
|
||||||
} else {
|
} else {
|
||||||
char uids[15];
|
char uids[15];
|
||||||
|
char card_datas[34];
|
||||||
sprintf(uids,"");
|
sprintf(uids,"");
|
||||||
for (uint8_t i = 0;i < uid_len;i++) {
|
for (uint8_t i = 0;i < uid_len;i++) {
|
||||||
sprintf(uids,"%s%02X",uids,uid[i]);
|
sprintf(uids,"%s%02X",uids,uid[i]);
|
||||||
}
|
}
|
||||||
|
if (uid_len == 4) { // Lets try to read block 0 of the mifare classic card for more information
|
||||||
|
uint8_t keyuniversal[6] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
|
||||||
|
if (mifareclassic_AuthenticateBlock (uid, uid_len, 1, 1, keyuniversal)) {
|
||||||
|
if (mifareclassic_ReadDataBlock(1, card_data)) {
|
||||||
|
memcpy(&card_datas,card_data,sizeof(card_data)); // Cast block 0 to a string
|
||||||
|
}
|
||||||
|
if (pn532_i2c_function == 1) { // erase block 1 of card
|
||||||
|
for (uint8_t i = 0;i<16;i++) {
|
||||||
|
card_data[i] = 0x00;
|
||||||
|
}
|
||||||
|
if (mifareclassic_WriteDataBlock(1, card_data)) {
|
||||||
|
erase_success = true;
|
||||||
|
snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Erase success");
|
||||||
|
AddLog(LOG_LEVEL_INFO);
|
||||||
|
memcpy(&card_datas,card_data,sizeof(card_data)); // Cast block 0 to a string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (pn532_i2c_function == 2) {
|
||||||
|
memcpy(&card_data,&pn532_i2c_newdata,sizeof(card_data));
|
||||||
|
if (mifareclassic_WriteDataBlock(1, card_data)) {
|
||||||
|
set_success = true;
|
||||||
|
snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Data write successful");
|
||||||
|
AddLog(LOG_LEVEL_INFO);
|
||||||
|
memcpy(&card_datas,card_data,sizeof(card_data)); // Cast block 0 to a string
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sprintf(card_datas,"AUTHFAIL");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (pn532_i2c_function) {
|
||||||
|
case 0x01:
|
||||||
|
if (!erase_success) {
|
||||||
|
snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Erase fail - exiting erase mode");
|
||||||
|
AddLog(LOG_LEVEL_INFO);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
if (!set_success) {
|
||||||
|
snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Write failed - exiting set mode");
|
||||||
|
AddLog(LOG_LEVEL_INFO);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pn532_i2c_function = 0;
|
||||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str());
|
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str());
|
||||||
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"UID\":\"%s\"}}"), mqtt_data, uids);
|
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"UID\":\"%s\", \"DATA\":\"%s\"}}"), mqtt_data, uids, card_datas);
|
||||||
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
|
MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_SENSOR), Settings.flag.mqtt_sensor_retain);
|
||||||
char command[27];
|
|
||||||
sprintf(command,"event PN532=%s",uids);
|
#ifdef USE_PN532_CAUSE_EVENTS
|
||||||
|
|
||||||
|
char command[64];
|
||||||
|
sprintf(command,"event PN532_UID=%s",uids);
|
||||||
ExecuteCommand(command, SRC_RULE);
|
ExecuteCommand(command, SRC_RULE);
|
||||||
|
sprintf(command,"event PN532_DATA=%s",card_datas);
|
||||||
|
ExecuteCommand(command, SRC_RULE);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
pn532_i2c_scan_defer_report = 7; // Ignore tags found for two seconds
|
pn532_i2c_scan_defer_report = 7; // Ignore tags found for two seconds
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -304,6 +456,48 @@ void PN532_ScanForTag(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean PN532_Command(void)
|
||||||
|
{
|
||||||
|
boolean serviced = true;
|
||||||
|
uint8_t paramcount = 0;
|
||||||
|
if (XdrvMailbox.data_len > 0) {
|
||||||
|
paramcount=1;
|
||||||
|
} else {
|
||||||
|
serviced = false;
|
||||||
|
return serviced;
|
||||||
|
}
|
||||||
|
char sub_string[XdrvMailbox.data_len];
|
||||||
|
char sub_string_tmp[XdrvMailbox.data_len];
|
||||||
|
for (uint8_t ca=0;ca<XdrvMailbox.data_len;ca++) {
|
||||||
|
if ((' ' == XdrvMailbox.data[ca]) || ('=' == XdrvMailbox.data[ca])) { XdrvMailbox.data[ca] = ','; }
|
||||||
|
if (',' == XdrvMailbox.data[ca]) { paramcount++; }
|
||||||
|
}
|
||||||
|
UpperCase(XdrvMailbox.data,XdrvMailbox.data);
|
||||||
|
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"E")) {
|
||||||
|
pn532_i2c_function = 1; // Block 0 of next card/tag will be reset to 0x00...
|
||||||
|
snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Next scanned tag data block 1 will be erased");
|
||||||
|
AddLog(LOG_LEVEL_INFO);
|
||||||
|
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str());
|
||||||
|
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"COMMAND\":\"E\"\"}}"), mqtt_data);
|
||||||
|
return serviced;
|
||||||
|
}
|
||||||
|
if (!strcmp(subStr(sub_string, XdrvMailbox.data, ",", 1),"S")) {
|
||||||
|
if (paramcount > 1) {
|
||||||
|
sprintf(sub_string_tmp,subStr(sub_string, XdrvMailbox.data, ",", 2));
|
||||||
|
uint8_t dlen = strlen(sub_string_tmp);
|
||||||
|
if (dlen > 15) { dlen = 15; }
|
||||||
|
memcpy(&pn532_i2c_newdata,&sub_string_tmp,dlen);
|
||||||
|
pn532_i2c_newdata[dlen] = 0x00; // Null terminate the string
|
||||||
|
pn532_i2c_function = 2;
|
||||||
|
snprintf_P(log_data, sizeof(log_data),"I2C: PN532 NFC - Next scanned tag data block 1 will be set to '%s'",pn532_i2c_newdata);
|
||||||
|
AddLog(LOG_LEVEL_INFO);
|
||||||
|
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("{\"" D_JSON_TIME "\":\"%s\""), GetDateAndTime(DT_LOCAL).c_str());
|
||||||
|
snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"PN532\":{\"COMMAND\":\"S\"\"}}"), mqtt_data);
|
||||||
|
return serviced;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
* Interface
|
* Interface
|
||||||
\*********************************************************************************************/
|
\*********************************************************************************************/
|
||||||
|
@ -322,6 +516,11 @@ boolean Xsns40(byte function)
|
||||||
case FUNC_EVERY_SECOND:
|
case FUNC_EVERY_SECOND:
|
||||||
PN532_Detect();
|
PN532_Detect();
|
||||||
break;
|
break;
|
||||||
|
case FUNC_COMMAND:
|
||||||
|
if (XSNS_40 == XdrvMailbox.index) {
|
||||||
|
result = PN532_Command();
|
||||||
|
}
|
||||||
|
break;
|
||||||
case FUNC_SAVE_BEFORE_RESTART:
|
case FUNC_SAVE_BEFORE_RESTART:
|
||||||
if (!pn532_i2c_disable) {
|
if (!pn532_i2c_disable) {
|
||||||
pn532_i2c_disable = 1;
|
pn532_i2c_disable = 1;
|
||||||
|
|
Loading…
Reference in New Issue