Merge pull request #21 from jjwbruijn/NFC-support

Nfc support
This commit is contained in:
Jelmer
2023-03-11 11:30:28 +01:00
committed by GitHub
13 changed files with 306 additions and 30 deletions

View File

@@ -5,7 +5,7 @@ BUILD ?= zbs29v033
SOURCES += main.c eeprom.c drawing.c
SOURCES += comms.c
SOURCES += syncedproto.c userinterface.c
SOURCES += powermgt.c barcode.c
SOURCES += powermgt.c barcode.c i2cdevices.c
all: #make sure it is the first target

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

127
tag_fw/i2cdevices.c Normal file
View File

@@ -0,0 +1,127 @@
// data / _command: 2.2
// _select 1.7
// busy 2.1
// reset 2.0
// spi.clk 0.0
// spi.mosi 0.1
#include "i2cdevices.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "cpu.h"
#include "i2c.h"
#include "printf.h"
#include "timer.h"
extern void dump(uint8_t* __xdata a, uint16_t __xdata l); // remove me when done
extern uint8_t __xdata blockXferBuffer[];
__xdata uint8_t i2cbuffer[18];
bool supportsNFCWake() {
P1PULL |= (1 << 3);
timerDelay(33300); // wait 25 ms
uint32_t pcount = 0;
P1PULL &= ~(1 << 3);
while (P1_3 && pcount < 10000) {
pcount++;
}
if (pcount < 10000) {
// P1_3 (Field Detect) dropped to 'low' pretty fast, this means the load on this pin is high
pr("This tag currently does not support NFC wake, load on the FD pin (P1.3) is pretty high.\nOn some boards, a pull-up resistor backpowers the NFC IC. Consider removing it!\n");
return false;
} else {
// No reason to believe this pin is currently loaded down severely
return true;
}
}
void loadRawNTag(uint16_t blocksize) {
struct I2cTransaction __xdata i2ctrans;
if (blocksize > 864) blocksize = 864;
uint8_t trcount = (uint8_t)(blocksize / 16);
if (blocksize % 16) trcount++;
for (uint8_t c = 0; c < trcount; c++) {
i2ctrans.numBytes = 17;
i2ctrans.deviceAddr = (uint8_t)0x55 << 1;
i2ctrans.bytes = i2cbuffer;
i2cbuffer[0] = c + 1;
memcpy(i2cbuffer + 1, blockXferBuffer + (c * 16), 16);
uint8_t res = i2cTransact(&i2ctrans, 1);
timerDelay(133300);
}
}
void loadURLtoNTag() {
// https://learn.adafruit.com/adafruit-pn532-rfid-nfc/ndef << very helpful
uint8_t __xdata i2cbuffer[18];
__xdata uint8_t* tempbuffer = blockXferBuffer + 2048;
strncpy(tempbuffer + 7, blockXferBuffer, 245);
uint8_t __xdata len = strlen(tempbuffer + 7);
struct I2cTransaction __xdata i2ctrans;
// TLV
tempbuffer[0] = 0x03; // NDEF message (TLV type)
tempbuffer[1] = 4 + len + 1;
// ndef record
tempbuffer[2] = 0xD1;
tempbuffer[3] = 0x01; // well known record type
tempbuffer[4] = len + 1; // payload length
tempbuffer[5] = 0x55; // payload type (URI record)
tempbuffer[6] = 0x00; // URI identifier code (no prepending)
len = 7 + len;
tempbuffer[len] = 0xFE;
uint8_t trcount = len / 16;
if (len % 16) trcount++;
for (uint8_t c = 0; c < trcount; c++) {
i2ctrans.numBytes = 17;
i2ctrans.deviceAddr = (uint8_t)0x55 << 1;
i2ctrans.bytes = i2cbuffer;
i2cbuffer[0] = c + 1;
memcpy(i2cbuffer + 1, tempbuffer + (c * 16), 16);
uint8_t res = i2cTransact(&i2ctrans, 1);
timerDelay(133300);
}
}
void i2cBusScan() {
struct I2cTransaction __xdata iictest;
iictest.numBytes = 0;
iictest.bytes = NULL;
pr("Starting I2C scan...\n");
for (uint8_t address = 0x00; address <= 0x7F; address++) {
iictest.deviceAddr = address << 1;
uint8_t res = i2cTransact(&iictest, 1);
if (res == 0) {
pr(" - Found i2c device at %02X\n", address);
}
timerDelay(13330);
}
pr("I2C scan complete\n");
}
bool i2cCheckDevice(uint8_t address) {
struct I2cTransaction __xdata iictest;
iictest.numBytes = 0;
iictest.deviceAddr = address << 1;
uint8_t res = i2cTransact(&iictest, 1);
if (res == 0) {
pr("Found i2c device at 0x%02X\n", address);
return true;
}
return false;
}

10
tag_fw/i2cdevices.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef _I2CDEV_H_
#define _I2CDEV_H_
#include <stdint.h>
bool supportsNFCWake();
void loadURLtoNTag();
void loadRawNTag(uint16_t blocksize);
bool i2cCheckDevice(uint8_t address);
#endif

View File

@@ -8,11 +8,13 @@
#include "asmUtil.h"
#include "comms.h" // for mLastLqi and mLastRSSI
#include "eeprom.h"
#include "screen.h"
#include "i2c.h"
#include "i2cdevices.h"
#include "powermgt.h"
#include "printf.h"
#include "proto.h"
#include "radio.h"
#include "screen.h"
#include "settings.h"
#include "syncedproto.h"
#include "timer.h"
@@ -22,7 +24,7 @@
// #define DEBUG_MODE
void displayLoop() {
powerUp(INIT_BASE | INIT_UART | INIT_GPIO);
powerUp(INIT_BASE | INIT_UART);
pr("Splash screen\n");
powerUp(INIT_EPD);
@@ -176,7 +178,22 @@ void main() {
}
}
pr("BOOTED> %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
pr("BOOTED> %d.%d.%d%s\n", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
#ifdef HAS_BUTTON
capabilities |= CAPABILITY_HAS_WAKE_BUTTON;
#endif
powerUp(INIT_I2C);
if (i2cCheckDevice(0x55)) {
powerDown(INIT_I2C);
capabilities |= CAPABILITY_HAS_NFC;
if (supportsNFCWake()) {
pr("This board supports NFC wake!\n");
capabilities |= CAPABILITY_NFC_WAKE;
}
} else {
powerDown(INIT_I2C);
}
pr("MAC>%02X%02X", mSelfMac[0], mSelfMac[1]);
pr("%02X%02X", mSelfMac[2], mSelfMac[3]);

View File

@@ -12,11 +12,12 @@
#include "cpu.h"
#include "drawing.h"
#include "eeprom.h"
#include "screen.h"
#include "i2c.h"
#include "i2cdevices.h"
#include "printf.h"
#include "proto.h"
#include "radio.h"
#include "screen.h"
#include "settings.h"
#include "sleep.h"
#include "syncedproto.h"
@@ -38,10 +39,12 @@ bool __xdata lowBattery = false;
uint16_t __xdata longDataReqCounter = 0;
uint16_t __xdata voltageCheckCounter = 0;
uint8_t __xdata capabilities = 0;
bool __xdata spiActive = false;
bool __xdata uartActive = false;
bool __xdata eepromActive = false;
bool __xdata i2cActive = false;
extern int8_t adcSampleTemperature(void); // in degrees C
void setupPortsInitial() {
@@ -118,7 +121,27 @@ static void configEEPROM(const bool setup) {
} else {
P1DIR |= (1 << 1);
}
setup == eepromActive;
setup == eepromActive; // wtf, this does nothing.
}
static void configI2C(const bool setup) {
if (setup == i2cActive) return;
if (setup) {
P1DIR &= ~(1 << 6);
P1_6 = 1;
P1FUNC |= (1 << 4) | (1 << 5);
P1PULL |= (1 << 4) | (1 << 5);
i2cInit();
i2cCheckDevice(0x50); // first transaction after init fails, this makes sure everything is ready for the first transaction
} else {
P1DIR |= (1 << 6);
P1_6 = 0;
P1FUNC &= ~((1 << 4) | (1 << 5));
P1PULL &= ~((1 << 4) | (1 << 5));
CLKEN &= ~0x10;
IEN1 &= ~4;
}
i2cActive = setup;
}
void powerUp(const uint8_t parts) {
@@ -171,13 +194,16 @@ void powerUp(const uint8_t parts) {
radioSetChannel(RADIO_FIRST_CHANNEL);
}
}
if (parts & INIT_I2C) {
configI2C(true);
}
}
void powerDown(const uint8_t parts) {
if (parts & INIT_UART) {
configUART(false);
}
if (parts & INIT_RADIO) { // warning; this also touches some stuff about the EEPROM, apparently. Re-init EEPROM afterwards
if (parts & INIT_RADIO) { // warning; this also touches some stuff about the EEPROM, apparently. Re-init EEPROM afterwards
radioRxEnable(false, true);
RADIO_IRQ4_pending = 0;
UNK_C1 &= ~0x81;
@@ -201,6 +227,9 @@ void powerDown(const uint8_t parts) {
if (!eepromActive && !epdGPIOActive) {
configSPI(false);
}
if (parts & INIT_I2C) {
configI2C(false);
}
}
void doSleep(const uint32_t __xdata t) {
@@ -232,13 +261,23 @@ void doSleep(const uint32_t __xdata t) {
#ifdef HAS_BUTTON
// Button setup on TEST pin 1.0 (input pullup)
P1FUNC &= ~(1 << 0);
P1DIR |= (1 << 0);
P1PULL |= (1 << 0);
P1LVLSEL |= (1 << 0);
P1INTEN = (1 << 0);
P1CHSTA &= ~(1 << 0);
P1FUNC &= ~(1 << 0);
P1DIR |= (1 << 0);
P1PULL |= (1 << 0);
P1LVLSEL |= (1 << 0);
P1INTEN = (1 << 0);
P1CHSTA &= ~(1 << 0);
#endif
if (capabilities & CAPABILITY_NFC_WAKE) {
P1FUNC &= ~(1 << 3);
P1DIR |= (1 << 3);
P1PULL |= (1 << 3);
P1LVLSEL |= (1 << 3);
P1INTEN = (1 << 3);
P1CHSTA &= ~(1 << 3);
}
// sleepy
sleepForMsec(t);
#ifdef HAS_BUTTON
@@ -247,6 +286,11 @@ void doSleep(const uint32_t __xdata t) {
wakeUpReason = WAKEUP_REASON_GPIO;
P1CHSTA &= ~(1 << 0);
}
if (P1CHSTA && (1 << 3) && capabilities & CAPABILITY_NFC_WAKE) {
wakeUpReason = WAKEUP_REASON_NFC;
P1CHSTA &= ~(1 << 3);
}
#endif
}

View File

@@ -11,7 +11,7 @@
#define INIT_EPD_VOLTREADING 0x80
#define INIT_RADIO 0x40
#define INIT_GPIO 0x20
#define INIT_I2C 0x20
#define INIT_UART 0x10
#define INIT_EPD 0x08
#define INIT_EEPROM 0x04
@@ -82,6 +82,8 @@ extern void initPowerSaving(const uint16_t initialValue);
extern uint8_t __xdata wakeUpReason;
extern uint8_t __xdata capabilities;
extern uint16_t __xdata nextCheckInFromAP;
extern uint8_t __xdata dataReqLastAttempt;
extern int8_t __xdata temperature;

View File

@@ -111,28 +111,32 @@ struct AvailDataReq {
uint16_t batteryMv;
uint8_t hwType;
uint8_t wakeupReason;
uint8_t capabilities; // undefined, as of now
uint8_t capabilities; // undefined, as of now
} __packed;
#define CAPABILITY_HAS_WAKE_BUTTON 0x20
#define CAPABILITY_HAS_NFC 0x40
#define CAPABILITY_NFC_WAKE 0x80
#define DATATYPE_NOUPDATE 0
#define DATATYPE_IMG_BMP 2
#define DATATYPE_FW_UPDATE 3
#define DATATYPE_IMG_DIFF 0x10 // always 1BPP
#define DATATYPE_IMG_RAW_1BPP 0x20 // 2888 bytes for 1.54" / 4736 2.9" / 15000 4.2"
#define DATATYPE_IMG_RAW_2BPP 0x21 // 5776 bytes for 1.54" / 9472 2.9" / 30000 4.2"
#define DATATYPE_IMG_RAW_1BPP_DIRECT 0x3F // only for 1.54", don't write to EEPROM, but straightaway to the EPD
#define DATATYPE_IMG_DIFF 0x10 // always 1BPP
#define DATATYPE_IMG_RAW_1BPP 0x20 // 2888 bytes for 1.54" / 4736 2.9" / 15000 4.2"
#define DATATYPE_IMG_RAW_2BPP 0x21 // 5776 bytes for 1.54" / 9472 2.9" / 30000 4.2"
#define DATATYPE_IMG_RAW_1BPP_DIRECT 0x3F // only for 1.54", don't write to EEPROM, but straightaway to the EPD
#define DATATYPE_NFC_RAW_CONTENT 0xA0 // raw memory content for the NT3H1101
#define DATATYPE_NFC_URL_DIRECT 0xA1 // URL format for NT3H1101
struct AvailDataInfo {
uint8_t checksum;
uint64_t dataVer; // MD5 of potential traffic
uint32_t dataSize;
uint8_t dataType;
uint64_t dataVer; // MD5 of potential traffic
uint32_t dataSize;
uint8_t dataType;
uint8_t dataTypeArgument; // extra specification or instruction for the tag (LUT to be used for drawing image)
uint16_t nextCheckIn; // when should the tag check-in again? Measured in minutes
uint16_t nextCheckIn; // when should the tag check-in again? Measured in minutes
} __packed;
struct blockPart {
uint8_t checksum;
uint8_t blockId;

View File

@@ -13,17 +13,17 @@
#include "cpu.h"
#include "drawing.h"
#include "eeprom.h"
#include "i2c.h"
#include "i2cdevices.h"
#include "powermgt.h"
#include "printf.h"
#include "proto.h"
#include "radio.h"
#include "screen.h"
#include "settings.h"
#include "sleep.h"
#include "timer.h"
#include "userinterface.h"
#include "wdt.h"
#include "screen.h"
// download-stuff
uint8_t __xdata blockXferBuffer[BLOCK_XFER_BUFFER_SIZE] = {0};
@@ -192,6 +192,7 @@ static void sendAvailDataReq() {
availreq->lastPacketLQI = mLastLqi;
availreq->temperature = temperature;
availreq->batteryMv = batteryVoltage;
availreq->capabilities = capabilities;
addCRC(availreq, sizeof(struct AvailDataReq));
commsTxNoCpy(outBuffer);
}
@@ -479,7 +480,7 @@ static bool getDataBlock(const uint16_t blockSize) {
partsThisBlock = BLOCK_MAX_PARTS;
memset(curBlock.requestedParts, 0xFF, BLOCK_REQ_PARTS_BYTES);
} else {
partsThisBlock = (sizeof(struct blockData)+blockSize) / BLOCK_PART_DATA_SIZE;
partsThisBlock = (sizeof(struct blockData) + blockSize) / BLOCK_PART_DATA_SIZE;
if (blockSize % BLOCK_PART_DATA_SIZE) partsThisBlock++;
memset(curBlock.requestedParts, 0x00, BLOCK_REQ_PARTS_BYTES);
for (uint8_t c = 0; c < partsThisBlock; c++) {
@@ -698,7 +699,7 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) {
}
xMemCopyShort(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
if (avail->dataSize > 4096) avail->dataSize = 4096;
if (getDataBlock(avail->dataSize)) {
powerUp(INIT_RADIO);
sendXferComplete();
@@ -792,6 +793,50 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) {
return false;
}
break;
case DATATYPE_NFC_URL_DIRECT:
case DATATYPE_NFC_RAW_CONTENT:
// Handle data for the NFC IC (if we have it)
// check if we actually have the capability to do NFC
if (!(capabilities & CAPABILITY_HAS_NFC)) {
// looks like we don't. mark as complete and then bail!
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
return true;
}
pr("NFC URL received\n");
if (curDataInfo.dataSize == 0 && xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & curDataInfo.dataVer, 8)) {
// we've already downloaded this NFC data, disregard and send XFC
pr("this was the same as the last transfer, disregard\n");
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
return true;
}
xMemCopyShort(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
uint16_t __xdata nfcsize = avail->dataSize;
if (getDataBlock(avail->dataSize)) {
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
curDataInfo.dataSize = 0; // mark as transfer not pending
powerUp(INIT_I2C);
if (avail->dataType == DATATYPE_NFC_URL_DIRECT) {
// only one URL (handle NDEF records on the tag)
loadURLtoNTag();
} else {
// raw NFC data upload to the NFC IC
loadRawNTag(nfcsize);
}
powerDown(INIT_I2C);
return true;
}
return false;
break;
}
return true;
}

View File

@@ -20,6 +20,7 @@
#include "spi.h"
#include "syncedproto.h" // for APmac / Channel
#include "timer.h"
#include "proto.h"
// extern uint8_t __xdata mSelfMac[8];
// extern uint8_t __xdata currentChannel;
@@ -29,9 +30,21 @@
const uint8_t __code fwVersion = FW_VERSION;
const char __code fwVersionSuffix[] = FW_VERSION_SUFFIX;
extern uint8_t __xdata capabilities;
bool __xdata lowBatteryShown = false;
bool __xdata noAPShown = false;
void addCapabilities() {
epdpr("Options: ");
if (capabilities & CAPABILITY_HAS_NFC) {
epdpr("-NFC ");
}
if (capabilities & CAPABILITY_HAS_WAKE_BUTTON) {
epdpr("-WAKE BUTTON" );
}
}
void addOverlay() {
if (currentChannel == 0) {
#if (SCREEN_WIDTH == 152)
@@ -83,6 +96,10 @@ void showSplashScreen() {
epdpr("%02X%02X", mSelfMac[1], mSelfMac[0]);
epdPrintEnd();
epdPrintBegin(2, 104, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
addCapabilities();
epdPrintEnd();
epdPrintBegin(2, 120, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
epdpr("zbs154v033 %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
epdPrintEnd();
@@ -95,6 +112,11 @@ void showSplashScreen() {
epdpr("Starting");
epdPrintEnd();
epdPrintBegin(64, 295, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
addCapabilities();
epdPrintEnd();
epdPrintBegin(80, 295, EPD_DIRECTION_Y, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
epdpr("zbs29v033 %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
epdPrintEnd();
@@ -106,6 +128,7 @@ void showSplashScreen() {
epdpr(":%02X:%02X", mSelfMac[1], mSelfMac[0]);
epdPrintEnd();
uint8_t __xdata buffer[17];
spr(buffer, "%02X%02X", mSelfMac[7], mSelfMac[6]);
spr(buffer + 4, "%02X%02X", mSelfMac[5], mSelfMac[4]);
@@ -126,6 +149,10 @@ void showSplashScreen() {
epdpr("Starting");
epdPrintEnd();
epdPrintBegin(2, 252, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
addCapabilities();
epdPrintEnd();
epdPrintBegin(3, 268, EPD_DIRECTION_X, EPD_SIZE_SINGLE, EPD_COLOR_BLACK);
epdpr("zbs42v033 %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
epdPrintEnd();
@@ -421,7 +448,7 @@ void showNoEEPROM() {
epdPrintEnd();
#endif
#if (SCREEN_WIDTH == 400) // 4.2"
epdPrintBegin(50 , 3, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
epdPrintBegin(50, 3, EPD_DIRECTION_X, EPD_SIZE_DOUBLE, EPD_COLOR_BLACK);
epdpr("EEPROM FAILED :(");
epdPrintEnd();
loadRawBitmap(failed, 176, 126, EPD_COLOR_RED);