diff --git a/tag_fw/Makefile b/tag_fw/Makefile index 180192c6..97559423 100644 --- a/tag_fw/Makefile +++ b/tag_fw/Makefile @@ -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 diff --git a/tag_fw/fw29-uc8151.bin b/tag_fw/fw29-uc8151.bin index abf073b8..ca3aa7ac 100644 Binary files a/tag_fw/fw29-uc8151.bin and b/tag_fw/fw29-uc8151.bin differ diff --git a/tag_fw/fw29.bin b/tag_fw/fw29.bin index 1f5ba229..342c2330 100644 Binary files a/tag_fw/fw29.bin and b/tag_fw/fw29.bin differ diff --git a/tag_fw/fw42.bin b/tag_fw/fw42.bin index 2197c5e4..84e3ec12 100644 Binary files a/tag_fw/fw42.bin and b/tag_fw/fw42.bin differ diff --git a/tag_fw/i2cdevices.c b/tag_fw/i2cdevices.c new file mode 100644 index 00000000..045ff7a9 --- /dev/null +++ b/tag_fw/i2cdevices.c @@ -0,0 +1,109 @@ +// 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 +#include +#include +#include +#include + +#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]; + +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; +} \ No newline at end of file diff --git a/tag_fw/i2cdevices.h b/tag_fw/i2cdevices.h new file mode 100644 index 00000000..abbe7a5d --- /dev/null +++ b/tag_fw/i2cdevices.h @@ -0,0 +1,9 @@ +#ifndef _I2CDEV_H_ +#define _I2CDEV_H_ +#include + +void loadURLtoNTag(); +void loadRawNTag(uint16_t blocksize); +bool i2cCheckDevice(uint8_t address); + +#endif \ No newline at end of file diff --git a/tag_fw/main.c b/tag_fw/main.c index 4b755a57..edc0c0ee 100644 --- a/tag_fw/main.c +++ b/tag_fw/main.c @@ -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" @@ -21,8 +23,10 @@ // #define DEBUG_MODE +uint8_t __xdata capabilities = 0; + void displayLoop() { - powerUp(INIT_BASE | INIT_UART | INIT_GPIO); + powerUp(INIT_BASE | INIT_UART); pr("Splash screen\n"); powerUp(INIT_EPD); @@ -178,6 +182,15 @@ void main() { pr("BOOTED> %d.%d.%d%s", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix); +#ifdef HAS_BUTTON + capabilities |= CAPABILITY_HAS_WAKE_BUTTON; +#endif + powerUp(INIT_I2C); + if (i2cCheckDevice(0x55)){ + capabilities |= CAPABILITY_HAS_NFC; + } + powerDown(INIT_I2C); + pr("MAC>%02X%02X", mSelfMac[0], mSelfMac[1]); pr("%02X%02X", mSelfMac[2], mSelfMac[3]); pr("%02X%02X", mSelfMac[4], mSelfMac[5]); diff --git a/tag_fw/powermgt.c b/tag_fw/powermgt.c index 6f5e68f3..f09c514f 100644 --- a/tag_fw/powermgt.c +++ b/tag_fw/powermgt.c @@ -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" @@ -41,7 +42,7 @@ uint16_t __xdata voltageCheckCounter = 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 +119,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 +192,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 +225,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) { diff --git a/tag_fw/powermgt.h b/tag_fw/powermgt.h index 6b39df32..54f36a3e 100644 --- a/tag_fw/powermgt.h +++ b/tag_fw/powermgt.h @@ -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 diff --git a/tag_fw/proto.h b/tag_fw/proto.h index 2ee3da03..a71d400e 100644 --- a/tag_fw/proto.h +++ b/tag_fw/proto.h @@ -111,28 +111,31 @@ 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 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; diff --git a/tag_fw/syncedproto.c b/tag_fw/syncedproto.c index 5a1f950f..b30fda44 100644 --- a/tag_fw/syncedproto.c +++ b/tag_fw/syncedproto.c @@ -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}; @@ -50,6 +50,9 @@ uint8_t __xdata currentChannel = 0; static uint8_t __xdata inBuffer[128] = {0}; static uint8_t __xdata outBuffer[128] = {0}; +// get capabilities from main.c +extern uint8_t __xdata capabilities; + // tools static uint8_t __xdata getPacketType(const void *__xdata buffer) { const struct MacFcs *__xdata fcs = buffer; @@ -192,6 +195,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 +483,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 +702,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 +796,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; } diff --git a/tag_fw/userinterface.c b/tag_fw/userinterface.c index 11b994c0..a5f077fc 100644 --- a/tag_fw/userinterface.c +++ b/tag_fw/userinterface.c @@ -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);