beta v0027 M2-7.5" FW

This commit is contained in:
jjwbruijn
2024-02-15 18:51:10 +01:00
parent f38e121c94
commit f2dc16953d
30 changed files with 802 additions and 2050 deletions

View File

@@ -1,5 +1,4 @@
MZ_FLASHER=python ../88MZ100_Flasher/88MZ100_Uart_flasher.py
ARMGCC=/usr/bin/
@@ -11,6 +10,7 @@ OBJCOPY=$(ARMGCC)arm-none-eabi-objcopy
#-Wall
CC_WARNING_FLAGS=-Wall -Wformat=0 -Wattributes -Wstrict-aliasing=0
CPP_FLAGS=-lstdc++ -mcpu=cortex-m3 -g -O3 -mthumb -fdata-sections -ffunction-sections -std=c++98 -std=gnu++0x
CPP0_FLAGS=-lstdc++ -mcpu=cortex-m3 -g -O0 -mthumb -fdata-sections -ffunction-sections -std=c++98 -std=gnu++0x
CC_FLAGS=-mcpu=cortex-m3 -g -O0 -mthumb -fdata-sections -ffunction-sections -std=c99
CC3_FLAGS=-mcpu=cortex-m3 -g -O3 -mthumb -fdata-sections -ffunction-sections -std=c99
CC_END_FLAGS=-lstdc++ -lc -lnosys -L. -T mz100/mz100.ld -fPIE --specs=nosys.specs -mcpu=cortex-m3 -mthumb -Wl,--gc-sections -O0 -flto -ffunction-sections -fdata-sections -DARM_GNU
@@ -35,7 +35,7 @@ compile:
@$(AS) -mcpu=cortex-m3 --gdwarf-2 -mthumb-interwork -o build/startup.o startup.S
@$(CC) $(CC3_FLAGS) -c mz100/core_cm3.c -o build/core_cm3.o
@$(CC) $(CC3_FLAGS) -c mz100/mz100_ssp.c -o build/mz100_ssp.o
@$(CC) $(CC3_FLAGS) -c mz100/mz100_wdt.c -o build/mz100_wdt.o
@$(CC) $(CC_FLAGS) -c mz100/mz100_wdt.c -o build/mz100_wdt.o
@$(CC) $(CC3_FLAGS) -c mz100/mz100_gpio.c -o build/mz100_gpio.o
@$(CC) $(CC3_FLAGS) -c mz100/mz100_driver.c -o build/mz100_driver.o
@$(CC) $(CC3_FLAGS) -c mz100/mz100_adc.c -o build/mz100_adc.o
@@ -43,7 +43,7 @@ compile:
@$(CC) $(CC3_FLAGS) -c mz100/mz100_clock.c -o build/mz100_clock.o
@$(CC) $(CC3_FLAGS) -c mz100/mz100_rtc.c -o build/mz100_rtc.o
@$(CC) $(CC3_FLAGS) -c mz100/mz100_pinmux.c -o build/mz100_pinmux.o
@$(CC) $(CC3_FLAGS) -c mz100/mz100_pmu.c -o build/mz100_pmu.o
@$(CC) $(CC_FLAGS) -c mz100/mz100_pmu.c -o build/mz100_pmu.o
@$(CC) $(CC3_FLAGS) -c mz100/mz100_qspi.c -o build/mz100_qspi.o
@$(CC) $(CC3_FLAGS) -c mz100/mz100_aes.c -o build/mz100_aes.o
@$(CC) $(CC3_FLAGS) -c mz100/mz100_gpt.c -o build/mz100_gpt.o
@@ -62,18 +62,24 @@ compile:
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c ../common/uzlib/src/tinflate.c -o build/uz-tinflate.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c ../common/uzlib/src/tinfzlib.c -o build/uz-tinfzlib.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -Wno-unknown-pragmas -c ../common/QRCode/src/qrcode.c -o build/qrcode.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c compression.cpp -o build/compression.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c drawing.cpp -o build/drawing.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c epd_interface.cpp -o build/epd_interface.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c powermgt.c -o build/powermgt.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c syncedproto.c -o build/syncedproto.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c powermgt.cpp -o build/powermgt.o
# @$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c syncedproto.c -o build/syncedproto.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLASGS) -c oepl-protocol.cpp -o build/oepl-protocol.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c comms.c -o build/comms.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c md5.c -o build/md5.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c settings.c -o build/settings.o
# @$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c settings.c -o build/settings.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c settings.cpp -o build/settings.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c mz100/timer.c -o build/timer.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c mz100/util.c -o build/util.o
@$(CC) $(CC3_FLAGS) $(CC_WARNING_FLAGS) -c mz100/gpio.c -o build/gpio.o
@$(CC) $(CC_FLAGS) $(CC_WARNING_FLAGS) -c mz100/gpio.c -o build/gpio.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c uc8159-var-m2.cpp -o build/uc8159-var-m2.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c userinterface.cpp -o build/userinterface.o
@$(GPLUSPLUS) $(CPP_FLAGS) $(CC_WARNING_FLAGS) -c main.cpp -o build/main.o
@@ -89,7 +95,7 @@ compile:
build/compression.o \
build/drawing.o \
build/powermgt.o \
build/syncedproto.o \
build/oepl-protocol.o \
build/comms.o \
build/settings.o \
build/timer.o \
@@ -99,6 +105,7 @@ compile:
build/uc8159-var-m2.o \
build/mz100_sleep.o \
build/core_cm3.o \
build/qrcode.o \
build/uz-adler32.o build/uz-crc32.o build/uz-defl_static.o build/uz-genlz77.o build/uz-tinfgzip.o build/uz-tinflate.o build/uz-tinfzlib.o \
build/mz100_ssp.o build/mz100_wdt.o build/mz100_gpio.o build/mz100_driver.o build/mz100_adc.o build/mz100_flash.o build/mz100_clock.o build/mz100_rtc.o build/mz100_pinmux.o build/mz100_pmu.o build/mz100_qspi.o build/mz100_aes.o build/mz100_gpt.o build/mz100_uart.o \
build/startup.o -o main.axf

View File

@@ -4,6 +4,7 @@
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
#include "epd_interface.h"

View File

@@ -16,6 +16,8 @@
#include "compression.h"
#include "oepl_fs.h"
#include "../common/QRCode/src/qrcode.h"
#include "../../oepl-definitions.h"
#include "../../oepl-proto.h"
@@ -23,802 +25,16 @@ extern "C" {
extern void dump(const uint8_t *a, const uint16_t l);
#include "mz100/util.h"
#include "mz100/mz100_flash.h"
#include "../common/QRCode/src/qrcode.h"
}
#include "userinterface.h"
#include "epd_interface.h"
#define EEPROM_XFER_BLOCKSIZE 512 // shouldn't be any less than 256 bytes probably
#define DRAWITEM_LIST_SIZE 24
struct __attribute__((packed)) imageHeader {
uint16_t width;
uint16_t height;
uint8_t bpp : 4;
uint8_t reserved : 4;
};
static drawItem *drawItems[DRAWITEM_LIST_SIZE] = {0};
void addBufferedImage(uint16_t x, uint16_t y, bool color, enum rotation ro, const uint8_t *image, bool mask) {
drawItem *di = new drawItem;
di->setRotation(ro);
if (di->direction ^ epd->drawDirectionRight) {
int16_t temp = x;
x = y;
y = temp;
}
uint16_t originalWidthBytes = (((uint16_t *)image)[0]) / 8;
uint16_t size = 0;
uint16_t width = ((uint16_t *)image)[0];
// find out if the original data was aligned in one byte; if not, add a byte
if (((uint16_t *)image)[0] % 8) originalWidthBytes++;
// if we're drawing in X direction, we shift the content here. Add extra space for shifting!
if (!di->direction) {
width += x % 8;
}
// check if the size is aligned in bytes; if not, add an extra for good measure;
if (width % 8) {
width /= 8;
width++;
} else {
width /= 8;
}
size = width * ((uint16_t *)image)[1];
size += 2; // not needed
uint8_t *im = (uint8_t *)calloc(size, 1);
for (uint16_t copyY = 0; copyY < ((uint16_t *)image)[1]; copyY++) {
memcpy(im + (copyY * width), image + 4 + (copyY * originalWidthBytes), originalWidthBytes);
// if we draw in X direction, we need to shift bytes in the array
if (!di->direction && (x % 8)) {
drawItem::shiftBytesRight(im + (copyY * width), x % 8, width);
}
}
di->addItem(im, width * 8, ((uint16_t *)image)[1]);
di->xpos = x;
di->ypos = y;
di->color = color;
if (mask)
di->type = drawItem::drawType::DRAW_MASK;
else
di->type = drawItem::drawType::DRAW_BUFFERED_1BPP;
di->addToList();
uint32_t __attribute__((always_inline)) inline HAL_flashRead(uint32_t address, uint8_t *buffer, uint32_t num){
return FLASH_Read(FLASH_FAST_READ_QUAD_OUT, address, buffer, num);
}
void addFlashImage(uint16_t x, uint16_t y, bool color, enum rotation ro, const uint8_t *image) {
drawItem *di = new drawItem;
di->setRotation(ro);
if (di->direction ^ epd->drawDirectionRight) {
int16_t temp = x;
x = y;
y = temp;
}
di->addItem((uint8_t *)(image + 4), ((uint16_t *)image)[0], ((uint16_t *)image)[1]);
di->xpos = x;
di->ypos = y;
di->color = color;
di->cleanUp = false;
di->type = drawItem::drawType::DRAW_BUFFERED_1BPP;
di->addToList();
}
void addFSImage(uint16_t x, uint16_t y, uint8_t color, enum rotation ro, char *name) {
drawItem *di = new drawItem;
di->setRotation(ro);
if (di->direction ^ epd->drawDirectionRight) {
int16_t temp = x;
x = y;
y = temp;
}
OEPLFile *file = fs->getFile(name);
if (!file) {
delete di;
return;
}
uint16_t width, height;
file->getBlock(0, (uint8_t *)&width, 2);
file->getBlock(2, (uint8_t *)&height, 2);
di->addItem((uint8_t *)file, width, height);
di->xpos = x;
di->ypos = y;
di->color = color;
di->cleanUp = true;
if (color == 2) {
di->type = drawItem::drawType::DRAW_OEPLFS_2BPP;
} else {
di->type = drawItem::drawType::DRAW_OEPLFS_1BPP;
}
di->addToList();
}
void addCompressedFSImage(uint16_t x, uint16_t y, enum rotation ro, char *name) {
drawItem *di = new drawItem;
di->type = drawItem::drawType::DRAW_COMPRESSED;
di->setRotation(ro);
if (di->direction ^ epd->drawDirectionRight) {
int16_t temp = x;
x = y;
y = temp;
}
decompress *decomp = new decompress;
if (!decomp->openFromFile(name)) {
delete di;
delete decomp;
return;
}
di->imageHeaderOffset = decomp->readByte(0);
struct imageHeader imgheader;
decomp->getBlock(1, (uint8_t *)&imgheader, sizeof(struct imageHeader));
di->addItem((uint8_t *)decomp, imgheader.width, imgheader.height);
di->xpos = x;
di->ypos = y;
di->color = imgheader.bpp;
di->cleanUp = true;
di->addToList();
}
void drawImageAtAddressWrap(uint32_t addr, uint8_t lut) {
// powerUp(INIT_EEPROM);
epdSetup();
selectLUT(lut);
uint8_t *xferbuffer = (uint8_t *)malloc(EEPROM_XFER_BLOCKSIZE);
struct EepromImageHeader *eih = (struct EepromImageHeader *)xferbuffer;
FLASH_Read(FLASH_NORMAL_READ, addr, xferbuffer, sizeof(struct EepromImageHeader));
switch (eih->dataType) {
case DATATYPE_IMG_RAW_1BPP: {
drawItem *di = new drawItem;
// di->setRotation(ro);
di->xpos = 0;
di->ypos = 0;
di->color = 0;
di->addItem((uint8_t *)addr, epd->effectiveXRes, epd->effectiveYRes);
di->type = drawItem::drawType::DRAW_EEPROM_1BPP;
di->direction = false;
di->cleanUp = false;
di->addToList();
} break;
case DATATYPE_IMG_RAW_2BPP: {
drawItem *di = new drawItem;
// di->setRotation(ro);
di->xpos = 0;
di->ypos = 0;
di->color = 0;
di->addItem((uint8_t *)addr, epd->effectiveXRes, epd->effectiveYRes);
di->type = drawItem::drawType::DRAW_EEPROM_2BPP;
di->direction = false;
di->cleanUp = false;
di->addToList();
} break;
case DATATYPE_IMG_ZLIB: {
drawItem *di = new drawItem;
decompress *decomp = new decompress;
di->type = drawItem::drawType::DRAW_COMPRESSED;
addr += sizeof(struct EepromImageHeader);
if (!decomp->openFromFlash(addr, eih->size)) {
delete di;
delete decomp;
return;
}
di->imageHeaderOffset = decomp->readByte(0);
struct imageHeader imgheader;
decomp->getBlock(1, (uint8_t *)&imgheader, sizeof(struct imageHeader));
di->addItem((uint8_t *)decomp, imgheader.width, imgheader.height);
di->xpos = 0;
di->ypos = 0;
if (imgheader.bpp == 1) di->color = 0;
if (imgheader.bpp == 2) di->color = 2;
di->cleanUp = true;
di->addToList();
} break;
}
free(xferbuffer);
addOverlay();
draw();
epdEnterSleep();
}
extern "C" {
void drawImageAtAddress(uint32_t addr, uint8_t lut) {
drawImageAtAddressWrap(addr, lut);
}
}
void drawRoundedRectangle(uint16_t xpos, uint16_t ypos, uint16_t width, uint16_t height, bool color) {
uint16_t widthBytes = width / 8;
if (width % 8) widthBytes++;
uint32_t framebufferSize = (widthBytes + 1) * height;
uint8_t *framebuffer = (uint8_t *)calloc(framebufferSize + 4, 1);
if (framebuffer == NULL) {
return;
}
((uint16_t *)framebuffer)[0] = width + 1;
((uint16_t *)framebuffer)[1] = height;
framebuffer += 4;
uint16_t w = width - 1;
uint16_t x = 1;
while (w--) {
framebuffer[(x / 8)] |= (uint8_t)(1 << (7 - ((uint8_t)x % 8)));
x++;
}
for (uint16_t curY = 1; curY < (height - 1); curY++) {
framebuffer[widthBytes * curY] = 0x80;
if (width % 8)
framebuffer[(widthBytes * curY) + widthBytes - 1] = (uint8_t)(1 << (7 - ((uint8_t)width % 8)));
else
framebuffer[(widthBytes * curY) + widthBytes - 1] = 0x01;
}
w = width - 1;
x = 1;
while (w--) {
framebuffer[(x / 8) + ((height - 1) * widthBytes)] |= (uint8_t)(1 << (7 - ((uint8_t)x % 8)));
x++;
}
framebuffer -= 4;
addBufferedImage(xpos, ypos, color, rotation::ROTATE_0, framebuffer, DRAW_NORMAL);
free(framebuffer);
}
void drawMask(uint16_t xpos, uint16_t ypos, uint16_t width, uint16_t height, bool color) {
uint16_t widthBytes = width / 8;
if (width % 8) widthBytes++;
uint32_t framebufferSize = widthBytes * height;
uint8_t *framebuffer = (uint8_t *)calloc(framebufferSize + 4, 1);
if (framebuffer == NULL) {
return;
}
((uint16_t *)framebuffer)[0] = width;
((uint16_t *)framebuffer)[1] = height;
framebuffer += 4;
for (uint16_t curY = 0; curY < height; curY++) {
uint16_t w = width;
uint16_t x = 0;
while (w--) {
framebuffer[(x / 8) + (curY * widthBytes)] |= (uint8_t)(1 << (7 - ((uint8_t)x % 8)));
x++;
}
}
framebuffer -= 4;
addBufferedImage(xpos, ypos, color, rotation::ROTATE_0, framebuffer, DRAW_INVERTED);
free(framebuffer);
}
// drawItem (sprite) functions
void drawItem::shiftBytesRight(uint8_t *data, uint8_t shift, uint8_t len) {
// Ensure the shift value is within bounds (0 to 7)
shift = shift % 8;
// Handle the case where shift is 0 or len is 0
if (shift == 0 || len == 0) {
return;
}
// Loop through the array from right to left
for (int i = len - 1; i > 0; i--) {
// Perform the shift by combining bits from the current byte
// and the next byte to its right
data[i] = (data[i] >> shift) | (data[i - 1] << (8 - shift));
}
// For the leftmost byte, simply shift it to the right
data[0] >>= shift;
}
uint8_t drawItem::bitReverse(uint8_t byte) {
byte = ((byte >> 1) & 0x55) | ((byte << 1) & 0xAA);
byte = ((byte >> 2) & 0x33) | ((byte << 2) & 0xCC);
byte = (byte >> 4) | (byte << 4);
return byte;
}
void drawItem::reverseBytes(uint8_t *src, uint8_t src_len) {
// Check for valid input
if (src == NULL || src_len == 0) {
return;
}
// Reverse the entire source array
for (uint8_t i = 0; i < src_len / 2; i++) {
uint8_t temp = src[i];
src[i] = src[src_len - i - 1];
src[src_len - i - 1] = temp;
}
// Reverse the bits within the bytes
for (uint8_t i = 0; i < src_len; i++) {
src[i] = bitReverse(src[i]);
}
}
void drawItem::copyWithByteShift(uint8_t *dst, uint8_t *src, uint8_t src_len, uint8_t offset) {
switch (type) {
case DRAW_MASK:
for (uint8_t i = 0; i < src_len; i++) {
dst[i + offset] &= ~(src[i]);
}
break;
default:
for (uint8_t i = 0; i < src_len; i++) {
dst[i + offset] |= src[i];
}
break;
}
}
void drawItem::renderDrawLine(uint8_t *line, uint16_t number, uint8_t c) {
drawItem *curDrawItem;
for (uint8_t i = 0; i < DRAWITEM_LIST_SIZE; i++) {
curDrawItem = drawItems[i];
if (curDrawItem != nullptr) {
curDrawItem->getDrawLine(line, number, c);
}
}
}
void drawItem::flushDrawItems() {
drawItem *curDrawItem;
for (uint8_t i = 0; i < DRAWITEM_LIST_SIZE; i++) {
curDrawItem = drawItems[i];
if (curDrawItem != nullptr) {
delete curDrawItem;
drawItems[i] = nullptr;
}
}
}
void drawItem::getXLine(uint8_t *line, uint16_t y, uint8_t c) {
switch (type) {
case DRAW_FONT:
case DRAW_BUFFERED_1BPP:
case DRAW_MASK:
if (c != color) return;
if ((y >= ypos) && (y < height + ypos)) { // was y > ypos, not >=
// y = height-y;
if (mirrorV) {
if (mirrorH) {
reverseBytes(&buffer[((height - (y - ypos)) * widthBytes)], widthBytes);
// reverseBytes(&buffer[((y - ypos) * widthBytes)], widthBytes);
} else {
reverseBytes(&buffer[((y - ypos) * widthBytes)], widthBytes);
}
}
if (mirrorH) {
copyWithByteShift(line, &buffer[((height - (y - ypos)) * widthBytes)], widthBytes, xpos / 8);
} else {
copyWithByteShift(line, &buffer[((y - ypos) * widthBytes)], widthBytes, xpos / 8);
}
}
break;
case DRAW_OEPLFS_1BPP:
case DRAW_OEPLFS_2BPP:
if ((color < 2) && (c != color)) return;
if ((y >= ypos) && (y < height + ypos)) { // was y > ypos, not >=
uint32_t offset = 4;
offset += c * height * widthBytes;
OEPLFile *file = (OEPLFile *)this->buffer;
uint8_t *dbuffer = (uint8_t *)malloc(widthBytes);
if (mirrorH) {
file->getBlock(offset + (height - (y - ypos)) * widthBytes, dbuffer, widthBytes);
} else {
file->getBlock(offset + (y - ypos) * widthBytes, dbuffer, widthBytes);
}
if (mirrorV) {
reverseBytes(dbuffer, widthBytes);
}
copyWithByteShift(line, dbuffer, widthBytes, xpos / 8);
free(dbuffer);
}
break;
case DRAW_COMPRESSED:
if ((color < 2) && (c != color)) return;
if ((y >= ypos) && (y < height + ypos)) {
uint32_t offset = this->imageHeaderOffset;
offset += c * height * widthBytes;
decompress *decomp = (decompress *)this->buffer;
uint8_t *dbuffer = (uint8_t *)malloc(widthBytes);
if (mirrorH) {
decomp->getBlock(offset + (height - (y - ypos)) * widthBytes, dbuffer, widthBytes);
} else {
decomp->getBlock(offset + (y - ypos) * widthBytes, dbuffer, widthBytes);
}
if (mirrorV) {
reverseBytes(dbuffer, widthBytes);
}
copyWithByteShift(line, dbuffer, widthBytes, xpos / 8);
free(dbuffer);
}
break;
case DRAW_EEPROM_1BPP:
if (c != color) return;
if (epd->drawDirectionRight)
y = epd->effectiveYRes - 1 - y;
FLASH_Read(FLASH_NORMAL_READ, (uint32_t)buffer + sizeof(struct EepromImageHeader) + (y * (epd->effectiveXRes / 8)), line, (epd->effectiveXRes / 8));
break;
case DRAW_EEPROM_2BPP:
if (epd->drawDirectionRight)
y = epd->effectiveYRes - 1 - y;
FLASH_Read(FLASH_NORMAL_READ, (uint32_t)(buffer + sizeof(struct EepromImageHeader) + ((y + (c * epd->effectiveYRes)) * (epd->effectiveXRes / 8))), line, (epd->effectiveXRes / 8));
break;
default:
printf("Not supported mode!\n");
break;
}
}
void drawItem::getYLine(uint8_t *line, uint16_t x, uint8_t c) {
switch (type) {
case DRAW_FONT:
case DRAW_BUFFERED_1BPP:
if (c != color) return;
if ((x >= xpos) && (x < width + xpos)) {
x -= xpos;
for (uint16_t curY = 0; curY < height; curY++) {
uint16_t curYMirrored = curY;
if (!mirrorH) curYMirrored = height - 1 - curY;
if (mirrorV) {
if (buffer[((width - x) / 8) + (curYMirrored * widthBytes)] & (1 << (7 - ((width - x) % 8)))) {
line[(curY + ypos) / 8] |= (1 << (7 - ((curY + ypos) % 8)));
}
} else {
if (buffer[(x / 8) + (curYMirrored * widthBytes)] & (1 << (7 - (x % 8)))) {
line[(curY + ypos) / 8] |= (1 << (7 - ((curY + ypos) % 8)));
}
}
}
}
break;
case DRAW_MASK:
if (c != color) return;
if ((x >= xpos) && (x < width + xpos)) {
x -= xpos;
for (uint16_t curY = 0; curY < height; curY++) {
uint16_t curYMirrored = curY;
if (!mirrorH) curYMirrored = height - 1 - curY;
if (mirrorV) {
if (buffer[((width - x) / 8) + (curYMirrored * widthBytes)] & (1 << (7 - ((width - x) % 8)))) {
line[(curY + ypos) / 8] &= ~(1 << (7 - ((curY + ypos) % 8)));
}
} else {
if (buffer[(x / 8) + (curYMirrored * widthBytes)] & (1 << (7 - (x % 8)))) {
line[(curY + ypos) / 8] &= ~(1 << (7 - ((curY + ypos) % 8)));
}
}
}
}
break;
case DRAW_OEPLFS_1BPP:
case DRAW_OEPLFS_2BPP:
// this is incredibly slow. For larger images, it'll probably read 128 bytes of eeprom for every -bit- in the image.
if ((color < 2) && (c != color)) return;
if ((x >= xpos) && (x < width + xpos)) {
uint32_t offset = 4;
offset += c * height * widthBytes;
OEPLFile *file = (OEPLFile *)this->buffer;
x -= xpos;
for (uint16_t curY = 0; curY < height; curY++) {
uint16_t curYMirrored = curY;
if (!mirrorH) curYMirrored = height - 1 - curY;
if (mirrorV) {
if (file->readByte(offset + ((width - x) / 8) + (curYMirrored * widthBytes)) & (1 << (7 - ((width - x) % 8)))) {
line[(curY + ypos) / 8] |= (1 << (7 - ((curY + ypos) % 8)));
}
} else {
if (file->readByte(offset + (x / 8) + (curYMirrored * widthBytes)) & (1 << (7 - (x % 8)))) {
line[(curY + ypos) / 8] |= (1 << (7 - ((curY + ypos) % 8)));
}
}
}
}
break;
default:
break;
}
}
void drawItem::getDrawLine(uint8_t *line, uint16_t number, uint8_t c) {
if (direction) {
getYLine(line, number, c);
} else {
getXLine(line, number, c);
}
}
void drawItem::addItem(uint8_t *data, uint16_t w, uint16_t h) {
width = w;
height = h;
widthBytes = w / 8;
if (w % 8) widthBytes++;
buffer = data;
}
bool drawItem::addToList() {
for (uint8_t i = 0; i < DRAWITEM_LIST_SIZE; i++) {
if (drawItems[i] == nullptr) {
drawItems[i] = this;
return true;
};
}
return false;
}
drawItem::~drawItem() {
if (cleanUp) {
switch (this->type) {
case drawItem::drawType::DRAW_OEPLFS_1BPP:
case drawItem::drawType::DRAW_OEPLFS_2BPP: {
OEPLFile *file = (OEPLFile *)this->buffer;
if (file) delete file;
} break;
case drawItem::drawType::DRAW_COMPRESSED: {
decompress *dec = (decompress *)this->buffer;
if (dec) delete dec;
} break;
default:
free(buffer);
break;
}
}
}
drawItem::drawItem() {
if (epd->drawDirectionRight) {
direction = true;
mirrorH = true;
}
}
void drawItem::setRotation(enum rotation ro) {
if (epd->drawDirectionRight) {
direction = true;
mirrorH = true;
}
switch (ro) {
case ROTATE_0:
break;
case ROTATE_270:
direction = !direction;
mirrorH = !mirrorH;
mirrorV = !mirrorV;
break;
case ROTATE_180:
mirrorH = !mirrorH;
mirrorV = !mirrorV;
break;
case ROTATE_90:
direction = !direction;
break;
};
}
// font rendering functions
fontrender::fontrender(char *name) {
this->setFont(name);
}
void fontrender::setFont(char *name) {
if (this->glyphFile) delete this->glyphFile;
if (this->bitmapFile) delete this->bitmapFile;
OEPLFile *font = fs->getFile(name);
if (!font)
printf("Couldn't open font file %s\n", name);
// else
// printf("Opened %s\n", name);
font->getBlock(0, (uint8_t *)&this->gfxFont, sizeof(GFXFontOEPL));
this->glyphFile = fs->getFile(this->gfxFont.glyphFile);
this->bitmapFile = fs->getFile(this->gfxFont.bitmapFile);
if (!this->glyphFile) printf("Couldn't open font file %s\n", name);
if (!this->bitmapFile) printf("Couldn't open font file %s\n", name);
if (font) delete (font);
}
fontrender::~fontrender() {
if (this->glyphFile) delete this->glyphFile;
if (this->bitmapFile) delete this->bitmapFile;
}
void fontrender::drawFastHLine(uint16_t x, uint16_t y, uint16_t w) {
while (w--) {
fb[(x / 8) + (y * bufferByteWidth)] |= (uint8_t)(1 << (7 - ((uint8_t)x % 8)));
x++;
}
}
void fontrender::fillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h) {
for (uint16_t curY = y; curY < y + h; curY++) {
drawFastHLine(x, curY, w);
}
}
uint8_t fontrender::getCharWidth(uint16_t c) {
if ((c >= gfxFont.first) && (c <= gfxFont.last)) {
c -= gfxFont.first;
// GFXglyph *glyph = &(((GFXglyph *)pgm_read_dword(&gfxFont->glyph))[c]);
GFXglyph glyph = this->getGlyph(c);
return glyph.xAdvance;
}
return 0;
}
uint8_t fontrender::drawChar(int32_t x, int32_t y, uint16_t c, uint8_t size) {
// Filter out bad characters not present in font
if ((c >= gfxFont.first) && (c <= gfxFont.last)) {
c -= gfxFont.first;
GFXglyph glyph = this->getGlyph(c);
// uint8_t *bitmap = (uint8_t *)gfxFont->bitmap;
uint32_t bo = glyph.bitmapOffset;
uint8_t w = glyph.width,
h = glyph.height;
int8_t xo = glyph.xOffset,
yo = glyph.yOffset;
uint8_t xx, yy, bits = 0, bit = 0;
int16_t xo16 = 0, yo16 = 0;
if (size > 1) {
xo16 = xo;
yo16 = yo;
}
// GFXFF rendering speed up
uint16_t hpc = 0; // Horizontal foreground pixel count
for (yy = 0; yy < h; yy++) {
for (xx = 0; xx < w; xx++) {
if (bit == 0) {
// bits = bitmap[bo++];
bits = (*this->bitmapFile)(bo++);
bit = 0x80;
}
if (bits & bit)
hpc++;
else {
if (hpc) {
if (size == 1)
drawFastHLine(x + xo + xx - hpc, y + yo + yy, hpc);
else
fillRect(x + (xo16 + xx - hpc) * size, y + (yo16 + yy) * size, size * hpc, size);
hpc = 0;
}
}
bit >>= 1;
}
// Draw pixels for this line as we are about to increment yy
if (hpc) {
if (size == 1)
drawFastHLine(x + xo + xx - hpc, y + yo + yy, hpc);
else
fillRect(x + (xo16 + xx - hpc) * size, y + (yo16 + yy) * size, size * hpc, size);
hpc = 0;
}
}
return glyph.xAdvance;
}
return 0;
}
void fontrender::epdPrintf(uint16_t x, uint16_t y, bool color, enum rotation ro, const char *c, ...) {
drawItem *di = new drawItem;
if (di == nullptr) return;
di->setRotation(ro);
// prepare a drawItem, exchange x/y if necessary.
if (di->direction ^ epd->drawDirectionRight) {
int16_t temp = x;
x = y;
y = temp;
}
// output string using vsnprintf
char out_buffer[256];
va_list lst;
va_start(lst, c);
uint8_t len = vsnprintf(out_buffer, 255, c, lst);
va_end(lst);
// account for offset in font rendering
if (!di->direction) {
Xpixels = x % 8; // total drawing width increased by x%8
} else {
Xpixels = 0;
}
// find out the total length of the string
for (uint8_t c = 0; c < len; c++) {
Xpixels += (uint16_t)getCharWidth(out_buffer[c]);
}
// find out the high and low points for given font
int8_t high = 0;
int8_t low = 0;
for (uint8_t curchar = 0; curchar < len; curchar++) {
uint8_t c = out_buffer[curchar];
if ((c >= gfxFont.first) && (c <= gfxFont.last)) {
c -= gfxFont.first;
GFXglyph g = this->getGlyph(c);
int8_t glyphUL = g.yOffset;
if (glyphUL < high) high = glyphUL;
int8_t glyphHeight = g.height;
if ((glyphUL + glyphHeight) > low) low = glyphUL + glyphHeight;
}
}
// Actual font height (reduces memory footprint)
int8_t height = -1 * (high - low) + 1;
// determine actual width
bufferByteWidth = Xpixels / 8;
if (Xpixels % 8) bufferByteWidth++;
// allocate framebuffer
fb = (uint8_t *)calloc(bufferByteWidth * height, 1);
if (!fb) {
printf("Failed to allocate buffer for drawitem, we can't render this text!\n");
printf("Tried to allocate a buffer %d x %d\n", bufferByteWidth, height);
delete di;
return;
}
uint16_t curX;
if (!di->direction) {
curX = x % 8; // start drawing at x%8s
} else {
curX = 0;
}
for (uint8_t c = 0; c < len; c++) {
curX += (uint16_t)drawChar(curX, height - low, out_buffer[c], 1);
}
di->addItem(fb, curX, height);
di->ypos = y;
di->xpos = x;
di->color = color;
di->type = drawItem::drawType::DRAW_FONT;
di->addToList();
}
GFXglyph fontrender::getGlyph(uint16_t c) {
GFXglyph g;
this->glyphFile->getBlock(sizeof(GFXglyph) * c, (uint8_t *)&g, sizeof(GFXglyph));
return g;
}
#include "../common/drawing.cpp"

View File

@@ -2,132 +2,13 @@
#define _DRAWING_H_
#include <stdint.h>
#define ENABLE_OEPLFS
#ifdef ENABLE_OEPLFS
#include "oepl_fs.h"
#define COLOR_RED 1
#define COLOR_BLACK 0
#define COLOR_DUAL 2
#define IMAGE_OR 1
#define IMAGE_REPLACE 0
#define DRAW_INVERTED 1
#define DRAW_NORMAL 0
#define FILENAME_LENGTH 32
typedef struct __attribute__ ((packed)) {
uint16_t bitmapOffset; ///< Pointer into GFXfont->bitmap
uint8_t width; ///< Bitmap dimensions in pixels
uint8_t height; ///< Bitmap dimensions in pixels
uint8_t xAdvance; ///< Distance to advance cursor (x axis)
int8_t xOffset; ///< X dist from cursor pos to UL corner
int8_t yOffset; ///< Y dist from cursor pos to UL corner
} GFXglyph;
enum rotation {
ROTATE_0,
ROTATE_90,
ROTATE_180,
ROTATE_270
};
typedef struct __attribute__ ((packed)) {
uint16_t first;
uint16_t last;
uint8_t yAdvance;
char glyphFile[FILENAME_LENGTH];
char bitmapFile[FILENAME_LENGTH];
} GFXFontOEPL;
extern "C"{
void drawImageAtAddress(uint32_t addr, uint8_t lut);
}
void addBufferedImage(uint16_t x, uint16_t y, bool color, enum rotation ro, const uint8_t *image, bool mask);
// void addFlashImage(uint16_t x, uint16_t y, bool color, enum rotation ro, const uint8_t *image);
void addQR(uint16_t x, uint16_t y, uint8_t version, uint8_t scale, const char *c, ...);
void drawRoundedRectangle(uint16_t xpos, uint16_t ypos, uint16_t width, uint16_t height, bool color);
void drawMask(uint16_t xpos, uint16_t ypos, uint16_t width, uint16_t height, bool color);
void addFSImage(uint16_t x, uint16_t y, uint8_t color, enum rotation ro, char *name);
void addCompressedFSImage(uint16_t x, uint16_t y, enum rotation ro, char *name);
class drawItem {
public:
drawItem();
~drawItem();
void setRotation(enum rotation ro);
void addItem(uint8_t *data, uint16_t width, uint16_t height);
bool addToList();
static void shiftBytesRight(uint8_t *data, uint8_t shift, uint8_t len);
static void renderDrawLine(uint8_t *line, uint16_t number, uint8_t c);
static void flushDrawItems();
// these are also used for rotated screens
static void reverseBytes(uint8_t *src, uint8_t src_len);
static uint8_t bitReverse(uint8_t byte);
enum drawType {
DRAW_FONT,
DRAW_BUFFERED_1BPP,
DRAW_MASK,
DRAW_EEPROM_1BPP,
DRAW_EEPROM_2BPP,
DRAW_COMPRESSED,
DRAW_OEPLFS_1BPP,
DRAW_OEPLFS_2BPP
} type;
int16_t xpos;
int16_t ypos;
enum rotation rotate = ROTATE_0;
uint8_t color = 0;
bool direction = false;
bool mirrorH = false;
bool mirrorV = false;
uint16_t width;
uint16_t height;
uint8_t imageHeaderOffset = 0;
// if this is true, clean up the reference (free memory).
bool cleanUp = true;
protected:
void copyWithByteShift(uint8_t *dst, uint8_t *src, uint8_t src_len, uint8_t offset);
void getDrawLine(uint8_t *line, uint16_t number, uint8_t c);
void getXLine(uint8_t *line, uint16_t yPos, uint8_t color);
void getYLine(uint8_t *line, uint16_t xPos, uint8_t color);
uint8_t widthBytes = 0;
uint8_t *buffer = nullptr;
};
class fontrender {
public:
void epdPrintf(uint16_t x, uint16_t y, bool color, enum rotation ro, const char *c, ...);
fontrender(char* name);
~fontrender();
void setFont(char* name);
protected:
GFXFontOEPL gfxFont;
uint16_t bufferByteWidth = 0;
uint8_t *fb = nullptr;
uint16_t Xpixels;
uint8_t drawChar(int32_t x, int32_t y, uint16_t c, uint8_t size);
uint8_t getCharWidth(uint16_t c);
void drawFastHLine(uint16_t x, uint16_t y, uint16_t w);
void fillRect(uint16_t x, uint16_t y, uint16_t w, uint16_t h);
GFXglyph getGlyph(uint16_t c);
OEPLFile *glyphFile = nullptr;
OEPLFile *bitmapFile = nullptr;
};
#endif
#include "../common/drawing.h"
#endif

View File

@@ -23,21 +23,24 @@ extern "C" {
#include "mz100/util.h"
}
#include "settings.h"
#include "../../oepl-definitions.h"
#include "../../oepl-proto.h"
epdInterface *epd;
__attribute__((section(".aonshadow"))) epdInterface *epd;
__attribute__((section(".aonshadow"))) tagSpecs tag;
epdInterface::~epdInterface(){
}
void epdSetup() {
epd = new uc8159;
epd->effectiveXRes = 640;
epd->effectiveYRes = 384;
epd->Xres = 640;
epd->Yres = 384;
epd->effectiveXRes = tagProfile.xRes;
epd->effectiveYRes = tagProfile.yRes;
epd->Xres = tagProfile.xRes;
epd->Yres = tagProfile.yRes;
epd->bpp = tagProfile.bpp;
epd->epdSetup();
}

View File

@@ -1,5 +1,5 @@
#pragma once
//#include <stdio.h>
// #include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
@@ -20,13 +20,26 @@ class epdInterface {
uint16_t effectiveYRes;
uint16_t XOffset = 0;
uint16_t YOffset = 0;
uint8_t bpp = 0;
bool drawDirectionRight = false;
bool epdMirrorV = false;
bool epdMirrorH = false;
};
struct tagSpecs {
uint8_t buttonCount = 0;
bool hasNFC = false;
bool hasLED = false;
uint16_t macSuffix = 0x0000;
uint8_t OEPLtype = 0;
uint8_t solumType = 0;
uint32_t imageSize = 0;
} __attribute__((packed));
extern __attribute__((section(".aonshadow"))) tagSpecs tag;
//__attribute__((section(".aonshadow")))
extern epdInterface* epd;
extern epdInterface *epd;
void epdSetup();
void epdEnterSleep();

View File

@@ -6,10 +6,13 @@
#include <stdlib.h>
#include "epd_interface.h"
extern "C" {
#include "powermgt.h"
#include "main.h"
#include "settings.h"
extern "C" {
#include "comms.h"
#include "mz100/core_cm3.h"
#include "mz100/eeprom.h"
@@ -25,11 +28,9 @@ extern "C" {
#include "mz100/mz100_sleep.h"
#include "mz100/mz100_ssp.h"
#include "mz100/mz100_uart.h"
#include "powermgt.h"
#include "mz100/printf.h"
#include "proto.h"
#include "settings.h"
#include "syncedproto.h"
#include "mz100/timer.h"
#include "mz100/util.h"
@@ -37,6 +38,8 @@ extern "C" {
extern void dump(const uint8_t *a, const uint16_t l);
}
#include "oepl-protocol.h"
#include "compression.h"
#include "userinterface.h"
@@ -50,7 +53,6 @@ uint64_t __attribute__((section(".default_mac"))) default_mac = SW_DEFAULT_MAC;
char macStr[32];
char macStr1[32];
// uint8_t mSelfMac[8];
#define TAG_MODE_CHANSEARCH 0
#define TAG_MODE_ASSOCIATED 1
@@ -78,17 +80,18 @@ bool protectedFlashWrite(uint32_t address, uint8_t *buffer, uint32_t num) {
return false;
}
static void prvGetSelfMac(void) {
FLASH_Read((FLASH_ReadMode_Type)0, EEPROM_MAC_INFO_START, mSelfMac, 8);
static void initTagProfile() {
for (uint8_t c = 0; c < 8; c++) {
mSelfMac[c] = tagProfile.macAddress[7 - c];
}
if ((((uint32_t *)mSelfMac)[0] | ((uint32_t *)mSelfMac)[1]) == 0 || (((uint32_t *)mSelfMac)[0] & ((uint32_t *)mSelfMac)[1]) == 0xffffffff) { // fastest way to check for all ones or all zeroes
printf("mac unknown\r\n");
// Write a blank mac to have something to work with.
memcpy(&mSelfMac, (uint8_t *)&default_mac, 8);
FLASH_Write((FLASH_ProgramMode_Type)0, EEPROM_MAC_INFO_START, mSelfMac, 8);
// sleep_with_with_wakeup(0);
printf("MAC: mac unknown, taking random Flash ID\n");
*((uint64_t *)&tagProfile.macAddress) = FLASH_GetUniqueID();
}
tag.imageSize = flashRoundUp(sizeof(struct EepromImageHeader) + (tagProfile.xRes * tagProfile.yRes * tagProfile.bpp) / 8);
tag.OEPLtype = 0x05;
}
uint8_t showChannelSelect() { // returns 0 if no accesspoints were found
@@ -147,6 +150,7 @@ uint8_t channelSelect() { // returns 0 if no accesspoints were found
void __attribute__((interrupt)) NMIException(void) {
printf("-----------> NMIException\r\n");
delay(1000);
PMU->CLK_SRC.BF.MAIN_CLK_SOURCE = 1;
PMU->PWR_MODE.BF.PWR_MODE = 0;
NVIC_SystemReset();
@@ -181,25 +185,42 @@ void __attribute__((interrupt)) UsageFaultException(void) {
}
void __attribute__((interrupt)) SVCHandler(void) {
printf("-----------> SVCHandler\r\n");
PMU->CLK_SRC.BF.MAIN_CLK_SOURCE = 1;
PMU->PWR_MODE.BF.PWR_MODE = 0;
NVIC_SystemReset();
}
void __attribute__((interrupt)) DebugMonitor(void) {
printf("-----------> DebugMonitor\r\n");
PMU->CLK_SRC.BF.MAIN_CLK_SOURCE = 1;
PMU->PWR_MODE.BF.PWR_MODE = 0;
NVIC_SystemReset();
}
void __attribute__((interrupt)) PendSVC(void) {
printf("-----------> PendSVC\r\n");
PMU->CLK_SRC.BF.MAIN_CLK_SOURCE = 1;
PMU->PWR_MODE.BF.PWR_MODE = 0;
NVIC_SystemReset();
}
void setupRTC() {
CLK_Xtal32MEnable(CLK_OSC_INTERN);
while (!CLK_GetClkStatus(CLK_OUT_XTAL64M))
;
int32_t setupRTC(uint32_t calibrate) {
// CLK_Xtal32MEnable(CLK_OSC_INTERN);
// while (!CLK_GetClkStatus(CLK_OUT_XTAL64M))
// ;
RC32K_CalClk_Div(63, 31);
CLK_ModuleClkEnable(CLK_RC32K_CAL);
CLK_RC32KEnable();
while (!CLK_GetClkStatus(CLK_OUT_RC32K))
;
PMU->RC32K_CAL_CNTL.BF.RC32K_CAL_DIV = 0;
CLK_RC32KCalibration(CLK_RC32KCAL_XTAL64M, CLK_AUTO_CAL, 0);
int32_t calres;
if (!calibrate) {
calres = CLK_RC32KCalibration(CLK_RC32KCAL_XTAL64M, CLK_AUTO_CAL, 0);
} else {
calres = CLK_RC32KCalibration(CLK_RC32KCAL_XTAL64M, CLK_MANUAL_CAL, calibrate);
}
CLK_ModuleClkEnable(CLK_RTC);
CLK_RTCClkSrc(CLK_RTC_RC32K);
RTC_Stop();
@@ -212,6 +233,7 @@ void setupRTC() {
NVIC_ClearPendingIRQ(RTC_IRQn);
RTC_IntMask(RTC_INT_CNT_UPP, UNMASK);
NVIC_EnableIRQ(RTC_IRQn);
return calres;
}
void setupUART() {
@@ -238,17 +260,6 @@ void setupUART() {
// UART 1 DEBUG OUT
}
void setupWDT() {
//** WATCHDOG
CLK_ModuleClkEnable(CLK_WDT);
WDT_SetMode(WDT_MODE_RESET);
WDT_SetResetPulseLen(WDT_RESET_PULSE_LEN_256);
WDT_SetTimeoutVal(30);
WDT_RestartCounter();
WDT_Enable();
//** WATCHDOG
}
void setupGPIO() {
//** GPIOS
init_GPIO_boot();
@@ -265,9 +276,9 @@ void setupGPIO() {
}
}
void setupCLKCalib() {
int32_t setupCLKCalib() {
(*(volatile unsigned int *)0x4A070004) = ((*(volatile unsigned int *)0x4A070004) & 0xFFFFFFE0) + 2;
PMU->PWR_MODE.BF.PWR_MODE = 2;
// PMU->PWR_MODE.BF.PWR_MODE = 2; // hmmm
uint32_t v0 = FLASH_WordRead(FLASH_NORMAL_READ, 4u);
char v1;
if (!(~v0 << 25)) {
@@ -276,13 +287,14 @@ void setupCLKCalib() {
;
v1 = CLK_RC32MCalibration(CLK_AUTO_CAL, 0);
FLASH_WordWrite(FLASH_PROGRAM_NORMAL, 4u, (v0 & 0xFFFFFF00) | (v1 & 0x7F));
return v1;
}
return -1;
}
void TagAssociated() {
// associated
struct AvailDataInfo *avail;
printf("longDataReqCounter = %d\n", longDataReqCounter);
// Is there any reason why we should do a long (full) get data request (including reason, status)?
if ((longDataReqCounter > LONG_DATAREQ_INTERVAL) || wakeUpReason != WAKEUP_REASON_TIMED) {
// check if we should do a voltage measurement (those are pretty expensive)
@@ -302,9 +314,10 @@ void TagAssociated() {
if (curImgSlot != 0xFF) {
powerUp(INIT_EEPROM | INIT_EPD);
wdt60s();
drawImageFromEeprom(curImgSlot);
drawImageFromEeprom(curImgSlot, 0);
powerDown(INIT_EEPROM | INIT_EPD);
} else {
WDT_RestartCounter();
powerUp(INIT_EPD);
showAPFound();
powerDown(INIT_EPD);
@@ -314,6 +327,7 @@ void TagAssociated() {
powerUp(INIT_RADIO);
printf("full request\n");
avail = getAvailDataInfo();
avail = getAvailDataInfo();
powerDown(INIT_RADIO);
if (avail != NULL) {
@@ -389,7 +403,7 @@ void TagChanSearch() {
wdt60s();
if (curImgSlot != 0xFF) {
powerUp(INIT_EEPROM);
drawImageFromEeprom(curImgSlot);
drawImageFromEeprom(curImgSlot, 0);
powerDown(INIT_EEPROM);
} else if ((scanAttempts >= (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS - 1))) {
showLongTermSleep();
@@ -401,12 +415,13 @@ void TagChanSearch() {
// did we find a working channel?
if (currentChannel) {
printf("PROTO: Found a working channel from the TagChanSearch loop\n");
// now associated! set up and bail out of this loop.
scanAttempts = 0;
wakeUpReason = WAKEUP_REASON_NETWORK_SCAN;
initPowerSaving(INTERVAL_BASE);
doSleep(getNextSleep() * 1000UL);
currentTagMode = TAG_MODE_ASSOCIATED;
sleep_with_with_wakeup(getNextSleep() * 1000UL);
return;
} else {
// still not associated
@@ -419,65 +434,80 @@ int main(void) {
(*(volatile unsigned int *)0xE000ED08) = 0x20100000; // Vector table in RAM and offset 0x4000
(*(volatile unsigned int *)0xE000E41A) = 0x40; // ??
timerInit();
CLK_SystemClkInit(CLK_SYS_XTAL64M, CLK_SYS_64M);
CLK_Xtal32MEnable(CLK_OSC_INTERN);
while (CLK_GetClkStatus(CLK_OUT_XTAL64M) != 1)
;
setupUART();
setupCLKCalib();
if (!loadValidateAonRam() || PMU_GetLastResetCause()) {
setupWDT();
// cold boot!
// calibrate the 32K RC oscillator (autocal), we'll store the result to flash later
uint32_t rtccal = setupRTC(0);
setupGPIO();
setupCLKCalib();
setupUART();
// fs = new OEPLFs();
printf("Rst reason: %i\r\n", PMU_GetLastResetCause());
printf("AON is not valid!\n");
setupRTC();
timerInit();
setupWDT();
clearAonRam();
prvGetSelfMac();
// all variables are set to 0 now. This might not be appropriate for all variables, such as:
curImgSlot = 0xFF;
// try to load settings
if (!loadSettings()) {
// if we couldn't load settings, we'll try to get it from the tagprofile file. Useful during development
fs->init();
if (!loadProfileFromFile((char *)"tagprofile.bin")) {
// whoops. Empty profile, that shouldn't really ever happen, ever.
printf("We don't know the type of this tag. That's kinda bad, I guess...\n");
} else {
fs->deleteFile((char *)"tagprofile.bin");
}
}
printf("MAIN: MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n", tagProfile.macAddress[0], tagProfile.macAddress[1], tagProfile.macAddress[2], tagProfile.macAddress[3], tagProfile.macAddress[4], tagProfile.macAddress[5], tagProfile.macAddress[6], tagProfile.macAddress[7]);
tagProfile.RC32Kcal = rtccal;
printf("MAIN: Rst reason: %i\r\n", PMU_GetLastResetCause());
initTagProfile();
wdt10s();
showSplashScreen();
delay(10000);
currentChannel = 0;
zigbeeCalibData.isValid = false;
wakeUpReason = WAKEUP_REASON_FIRSTBOOT;
initializeProto();
printf("Erz data\r\n");
initPowerSaving(INTERVAL_BASE);
loadDefaultSettings();
doVoltageReading();
// qspiEraseRange(EEPROM_SETTINGS_AREA_START, EEPROM_SETTINGS_AREA_LEN);
sprintf(macStr, "(" MACFMT ")", MACCVT(mSelfMac));
currentChannel = showChannelSelect();
WDT_RestartCounter();
if (currentChannel) {
printf("AP Found\r\n");
printf("MAIN: AP Found\r\n");
wdt10s();
delay(10000);
showAPFound();
sprintf(macStr1, "OpenEPaperLink Ch: %i", currentChannel);
sprintf(macStr1, "MAIN: OpenEPaperLink Ch: %i", currentChannel);
wdt10s();
timerDelay(TIMER_TICKS_PER_MSEC * 1000);
currentTagMode = TAG_MODE_ASSOCIATED;
} else {
printf("No AP found\r\n");
wdt10s();
delay(10000);
showNoAP();
sleep_with_with_wakeup(120000UL);
wdt10s();
timerDelay(TIMER_TICKS_PER_MSEC * 1000);
currentTagMode = TAG_MODE_CHANSEARCH;
}
powerUp(INIT_UART);
writeSettings();
} else {
setupWDT(); // turn me off
setupRTC(tagProfile.RC32Kcal);
setupWDT();
setupGPIO();
setupCLKCalib(); // turn me off
// setupUART();// turn me off
// setupRTC();// turn me off
memset(curBlock.requestedParts, 0x00, BLOCK_REQ_PARTS_BYTES);
powerUp(INIT_UART);
// fs = new OEPLFs();
timerInit();
}
while (1) {
@@ -503,30 +533,29 @@ void _putchar(char c) {
_write(0, &c, 1);
}
void applyUpdate() {
uint32_t ofst, now, size, pieceSz = 0x2000;
void applyUpdate(uint32_t size) {
uint32_t ofst, now, pieceSz = 0x2000;
uint8_t chunkStore[0x2000];
printf("Applying update\r\n");
// apparently, the flash process is more reliable if we do these two first
setupCLKCalib();
setupRTC();
setupRTC(0);
showApplyUpdate();
printf("Applying update\r\n");
qspiEraseRange(EEPROM_OS_START, EEPROM_OS_LEN);
// qspiEraseRange(EEPROM_OS_START, EEPROM_OS_LEN);
size = EEPROM_OS_LEN;
for (ofst = 0; ofst < size; ofst += now) {
now = size - ofst;
if (now > pieceSz)
now = pieceSz;
printf("Cpy 0x%06x + 0x%04x to 0x%06x\r\n", EEPROM_UPDATE_START + ofst, now, EEPROM_OS_START + ofst);
FLASH_Read((FLASH_ReadMode_Type)0, EEPROM_UPDATE_START + ofst, chunkStore, now);
protectedFlashWrite(EEPROM_OS_START + ofst, chunkStore, now);
printf("Cpy 0x%06x + 0x%04x to 0x%06x\r\n", fsEnd + ofst, now, ofst);
FLASH_Read((FLASH_ReadMode_Type)0, fsEnd + ofst, chunkStore, now);
// qspiEraseRange(ofst, now);
protectedFlashWrite(ofst, chunkStore, now);
WDT_RestartCounter();
}
printf("Resetting!\n");

View File

@@ -30,4 +30,4 @@
#define RADIO_FIRST_CHANNEL (11) //2.4-GHz channels start at 11
void applyUpdate();
void applyUpdate(uint32_t len);

View File

@@ -8,29 +8,16 @@
//pages are 4K in size
//an update can be stored in any 2 image slots
#define EEPROM_PAGE_SIZE (0x01000UL)
#define EEPROM_SETTINGS_AREA_START (0x7F000UL)
#define EEPROM_SETTINGS_SIZE (0x01000UL)
#define EEPROM_OS_START (0x00000UL)
#define EEPROM_OS_LEN (0x1FFFFUL) //0xE820 of image, rounded up to 4K
#define EEPROM_IMG_START (0x20000UL)
#define EEPROM_IMG_EACH (0x1F000UL)
#define EEPROM_IMG_LEN (EEPROM_IMG_START + 0x13FFFUL)
#define EEPROM_UPDATE_START (0x20000UL) //same header as images
#define EEPROM_UPDATE_LEN (0x1FFFFUL)
#define EEPROM_SETTINGS_AREA_START (0x14000UL)
#define EEPROM_SETTINGS_AREA_LEN (0x03000UL)
#define EEPROM_TOTAL_SIZE (0x80000UL)
#define EEPROM_MAC_INFO_START (0x6c000UL) //not same as stock
#define EEPROM_MAC_INFO_LEN (0x01000UL)
#define EEPROM_IMG_INPROGRESS (0x7fffffff)
#define EEPROM_IMG_VALID (0x494d4721)
//#define EEPROM_PIECE_SZ (88)
#include "../../common/eeprom_struct.h"

View File

@@ -1,6 +1,6 @@
#include "nfc.h"
//#include <stdio.h>
// #include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
@@ -14,38 +14,46 @@
#include "util.h"
#include "printf.h"
#include "mz100_clock.h"
void NVIC_some_IRQ1(unsigned int a1)
{
volatile bool RTCintFired = false;
void setupWDT() {
//** WATCHDOG
CLK_ModuleClkEnable(CLK_WDT);
WDT_SetMode(WDT_MODE_RESET);
WDT_SetResetPulseLen(WDT_RESET_PULSE_LEN_256);
WDT_SetTimeoutVal(30);
WDT_RestartCounter();
WDT_Enable();
//** WATCHDOG
}
void NVIC_some_IRQ1(unsigned int a1) {
*(uint32_t *)(4 * (a1 >> 5) - 0x1FFF1E80) = 1 << (a1 & 0x1F);
}
void NIVC_some_IRQ(unsigned int a1)
{
void NIVC_some_IRQ(unsigned int a1) {
*(uint32_t *)(4 * (a1 >> 5) - 0x1FFF1D80) = 1 << (a1 & 0x1F);
}
void Pin_pad_set_Low(int pin)
{
void Pin_pad_set_Low(int pin) {
GPIO_PinPadOutputEnable(pin);
GPIO_PinPadOutputLevel(pin, PIN_PAD_OUTPUT_LOW);
GPIO_PinOutputModeConfig(pin, PIN_OUTPUT_MODE_PAD);
}
void Pin_pad_set_High(int pin)
{
void Pin_pad_set_High(int pin) {
GPIO_PinPadOutputEnable(pin);
GPIO_PinPadOutputLevel(pin, PIN_PAD_OUTPUT_HIGH);
GPIO_PinOutputModeConfig(pin, PIN_OUTPUT_MODE_PAD);
}
void Pin_pad_set_Normal(int pin)
{
void Pin_pad_set_Normal(int pin) {
GPIO_PinPadOutputEnable(pin);
GPIO_PinPadOutputLevel(pin, PIN_PAD_OUTPUT_LOW);
GPIO_PinOutputModeConfig(pin, PIN_OUTPUT_MODE_NORMAL_FUNCTION);
}
void init_GPIO_boot()
{
void init_GPIO_boot() {
Pin_pad_set_Normal(NFC_POWER);
Pin_pad_set_Normal(NFC_IRQ);
Pin_pad_set_Normal(EPD_MOSI);
@@ -59,10 +67,9 @@ void init_GPIO_boot()
Pin_pad_set_Normal(EPD_RESET);
Pin_pad_set_Normal(EPD_HLT_CTRL);
}
void init_GPIO_sleep()
{
void init_GPIO_sleep() {
Pin_pad_set_Low(NFC_POWER);
//Pin_pad_set_Low(NFC_IRQ);
// Pin_pad_set_Low(NFC_IRQ);
Pin_pad_set_Low(EPD_MOSI);
Pin_pad_set_Low(EPD_MISO);
Pin_pad_set_Low(EPD_CLK);
@@ -77,10 +84,8 @@ void init_GPIO_sleep()
uint8_t WAKEUP_RF = 0;
void __attribute__((interrupt)) ExtPin5_IRQHandler(void)
{
if (!WAKEUP_RF)
{
void __attribute__((interrupt)) ExtPin5_IRQHandler(void) {
if (!WAKEUP_RF) {
NVIC_ClearPendingIRQ(ExtPin5_IRQn);
GPIO_IntMask(RF_WAKEUP_PIN, MASK);
NVIC_some_IRQ1(ExtPin5_IRQn);
@@ -90,10 +95,17 @@ void __attribute__((interrupt)) ExtPin5_IRQHandler(void)
}
}
uint32_t gSleepRtcCounter = 0;
uint8_t Ext_Pin27_triggered = 0;
void __attribute__((interrupt)) ExtPin27_IRQHandler(void)
{
void __attribute__((interrupt)) ExtPin7_IRQHandler(void) {
NVIC_ClearPendingIRQ(ExtPin7_IRQn);
GPIO_IntMask(NFC_IRQ, MASK);
NVIC_some_IRQ1(ExtPin7_IRQn);
PMU_ClearWakeupExtpin(PMU_GPIO7_INT);
NVIC_ClearPendingIRQ(ExtPin7_IRQn);
}
volatile uint32_t gSleepRtcCounter = 0;
volatile uint8_t Ext_Pin27_triggered = 0;
void __attribute__((interrupt)) ExtPin27_IRQHandler(void) {
WDT_RestartCounter();
printf(">>PIN_27_IRQHandler\r\n");
NVIC_ClearPendingIRQ(ExtPin27_IRQn);
@@ -104,33 +116,26 @@ void __attribute__((interrupt)) ExtPin27_IRQHandler(void)
Ext_Pin27_triggered = 1;
}
void enable_irq_for_pin(int a1, unsigned int a2)
{
PMU_WakeupPinSrc_Type v4; // r0
PMU_WakeupPinSrc_Type v5; // r5
char v6; // r7
PMU_WakeupTrigMode_Type v7; // r1
void enable_irq_for_pin(int a1, unsigned int a2) {
PMU_WakeupPinSrc_Type v4; // r0
PMU_WakeupPinSrc_Type v5; // r5
char v6; // r7
PMU_WakeupTrigMode_Type v7; // r1
GPIO_PinMuxFun(a2, 7);
if (a2 > 7)
{
if (a2 > 7) {
if (a2 - 26 > 5)
return;
v4 = a2 - 19;
}
else
{
} else {
v4 = a2 - 1;
}
v5 = v4;
v6 = a2 + 31;
if (a1 == 1)
{
if (a1 == 1) {
GPIO_PinModeConfig(a2, PINMODE_PULLDOWN);
v7 = PMU_WAKEUP_EDGE_RISING;
}
else
{
} else {
if (a1 != 2)
goto LABEL_11;
GPIO_PinModeConfig(a2, PINMODE_PULLUP);
@@ -144,13 +149,13 @@ LABEL_11:
NVIC_EnableIRQ(v6);
}
void wait_busy_sleep(int a1)
{
void wait_busy_sleep(int a1) {
unsigned int v1 = 0;
gSleepRtcCounter = 0;
printf("=> EPD_BUSYN_PIN : %d\r\n", 27);
while (1)
{
// printf("=> EPD_BUSYN_PIN : %d\r\n", 27);
delay(1);
while (1) {
RTC_CounterReset();
RTC_IntClr(RTC_INT_CNT_UPP);
NIVC_some_IRQ(0);
@@ -163,10 +168,7 @@ void wait_busy_sleep(int a1)
if (Ext_Pin27_triggered == 1)
break;
v1++;
delay(2000);
printf("busypin:%d,SCNT:%d\r\n", GPIO_ReadPinLevel(EPD_BUSY), v1);
if (v1 >= 0x5A)
{
if (v1 >= 0x5A) {
printf("DRF BUSY CHECK FAIL\r\n");
break;
}
@@ -176,7 +178,7 @@ void wait_busy_sleep(int a1)
NIVC_some_IRQ(0);
(*(volatile unsigned int *)0xE000E180) = 1;
gSleepRtcCounter = 1000 * RTC_GetCounterVal() / 0x7FFFu + a1 * v1;
printf("RTC_GetCounterVal(): %d, gSleepRtcCounter:%d(ms)\r\n", RTC_GetCounterVal(), gSleepRtcCounter);
// printf("RTC_GetCounterVal(): %d, gSleepRtcCounter:%d(ms)\r\n", RTC_GetCounterVal(), gSleepRtcCounter);
RTC_CounterReset();
Ext_Pin27_triggered = 0;
GPIO_SetPinDir(EPD_BUSY, GPIO_INPUT);
@@ -184,14 +186,13 @@ void wait_busy_sleep(int a1)
GPIO_PinModeConfig(EPD_BUSY, PINMODE_PULLUP);
}
void do_sleeped_epd_refresh()
{
void do_sleeped_epd_refresh() {
printf("PM2 MODE START!\r\n");
PMU->PMIP_BRN.BF.BRNDET_EN = 0;
PMU->PWR_MODE.BF.CAU_ON = 0;
PMU->PMIP_CHP_CTRL.BF.CHP_ON_OFF = 1;
PMU_SetSleepMode(PMU_PM2);
PMU_ClearWakeupExtpin(PMU_GPIO5_INT);
wait_busy_sleep(2000);
wait_busy_sleep(500);
printf("uDisTime : %d ms\r\n", gSleepRtcCounter);
}

View File

@@ -1,5 +1,7 @@
#pragma once
void setupWDT();
void NVIC_some_IRQ1(unsigned int a1);
void NIVC_some_IRQ(unsigned int a1);
void init_GPIO_boot();

View File

@@ -3,8 +3,8 @@ GROUP(-lgcc -lc -lnosys)
MEMORY
{
FLASH (rx) : ORIGIN = 0x100000, LENGTH = 80k
RAM (rwx) : ORIGIN = 0x20100000 + 80k, LENGTH = 160k - 80k - 2k
FLASH (rx) : ORIGIN = 0x100000, LENGTH = 90k
RAM (rwx) : ORIGIN = 0x20100000 + 90k, LENGTH = 160k - 90k - 2k
AONSHADOW (rwx) : ORIGIN = 0x20128000 - 2k, LENGTH = 2k
AON (rwx) : ORIGIN = 0x20130000 , LENGTH = 4k
}

View File

@@ -97,7 +97,7 @@ void sleep_with_with_wakeup(uint32_t sleep_time_ms)
//memcpy((uint8_t *)&(*(volatile unsigned int *)0x130500), (uint8_t *)&curBlock, sizeof(struct blockRequest));
//memcpy((uint8_t *)&(*(volatile unsigned int *)0x130600), (uint8_t *)&curDataInfo, sizeof(struct AvailDataInfo));
//sleep_time_ms = 10000;
printf("sleep! %u\n", sleep_time_ms);
//printf("sleep! %u\n", sleep_time_ms);
uint32_t sleep_time_ms_1;
AON_level_VDD(7);
AON_level_VAA(0);

View File

@@ -1,7 +1,7 @@
#include "util.h"
#include <stdarg.h>
//#include <stdio.h>
// #include <stdio.h>
#include "printf.h"
#include "eeprom.h"
@@ -12,7 +12,7 @@
#include "timer.h"
void wdt10s() {
WDT_RestartCounter();
WDT_RestartCounter();
}
void wdt30s() {
WDT_RestartCounter();
@@ -120,19 +120,19 @@ uint32_t measureBattery(void) {
void qspiEraseRange(uint32_t addr, uint32_t len) {
uint64_t time;
// round starting address down
if (addr % EEPROM_PAGE_SIZE) {
len += addr % EEPROM_PAGE_SIZE;
addr = addr / EEPROM_PAGE_SIZE * EEPROM_PAGE_SIZE;
if (addr % EEPROM_ERZ_SECTOR_SZ) {
len += addr % EEPROM_ERZ_SECTOR_SZ;
addr = addr / EEPROM_ERZ_SECTOR_SZ * EEPROM_ERZ_SECTOR_SZ;
}
// round length up
len = (len + EEPROM_PAGE_SIZE - 1) / EEPROM_PAGE_SIZE * EEPROM_PAGE_SIZE;
len = (len + EEPROM_ERZ_SECTOR_SZ - 1) / EEPROM_ERZ_SECTOR_SZ * EEPROM_ERZ_SECTOR_SZ;
while (len) {
uint32_t now;
bool ok;
WDT_RestartCounter();
//WDT_RestartCounter();
if (!(addr % 0x10000) && len >= 0x10000) {
ok = FLASH_Block64KErase(addr / 0x10000);
now = 0x10000;
@@ -156,16 +156,16 @@ void qspiEraseRange(uint32_t addr, uint32_t len) {
;
}
}
WDT_RestartCounter();
//WDT_RestartCounter();
}
bool eepromWrite(uint32_t addr, const void *srcP, uint16_t len) {
FLASH_Write(0, addr, (void*)srcP, len);
FLASH_Write(0, addr, (void *)srcP, len);
return true;
}
bool eepromErase(uint32_t addr, uint16_t nSec) {
qspiEraseRange(addr, nSec);
qspiEraseRange(addr, nSec*EEPROM_ERZ_SECTOR_SZ);
return true;
}
@@ -173,8 +173,18 @@ void eepromRead(uint32_t addr, void *dstP, uint16_t len) {
uint8_t *dst = (uint8_t *)dstP;
FLASH_Read(0, addr, dst, len);
}
extern __attribute__((section(".aonshadow"))) uint32_t fsEnd;
uint32_t eepromGetSize(void) {
return EEPROM_IMG_LEN;
return EEPROM_TOTAL_SIZE - fsEnd;
}
uint32_t flashRoundUp(uint32_t in) {
uint32_t temp = in / EEPROM_ERZ_SECTOR_SZ;
if (in % EEPROM_ERZ_SECTOR_SZ)
temp++;
return temp * EEPROM_ERZ_SECTOR_SZ;
}
void radioShutdown(void) {

View File

@@ -18,6 +18,8 @@ bool eepromWrite(uint32_t addr, const void *srcP, uint16_t len);
bool eepromErase(uint32_t addr, uint16_t nSec);
void eepromRead(uint32_t addr, void *dstP, uint16_t len);
uint32_t flashRoundUp(uint32_t in);
uint32_t eepromGetSize(void);
void radioShutdown(void); //experimentally written. suggest reset after use to bring radio back :)

View File

@@ -0,0 +1,90 @@
#include "oepl-protocol.h"
#include "powermgt.h"
#include "main.h"
extern "C" {
#include "board.h"
#include "comms.h"
#include "mz100/eeprom.h"
#include "mz100/mz100_sleep.h"
#include "mz100/printf.h"
#include "proto.h"
#include "mz100/timer.h"
#include "mz100/util.h"
#include "mz100/mz100_flash.h"
#include "zigbee.h"
#include "md5.h"
}
#include "drawing.h"
#include "oepl_fs.h"
#include "epd_interface.h"
#include "settings.h"
#define BLOCKSIZE_MS 270 // was 270
#define FW88MZ100
#define HAL_PacketRX commsRxUnenc
#define millis() timerGet()
#define HAL_TIMER_TICK TIMER_TICKS_PER_MSEC
void inline HAL_msDelay(uint32_t t) {
timerDelay(t * TIMER_TICKS_PER_MSEC);
}
void executeCommand(uint8_t c) {
}
void loadSettingsFromBuffer(uint8_t *buffer) {
}
#define EEPROM_IMG_START fsEnd
#define FW_LOC fsEnd
#define FW_METADATA_LOC 0
void dump(const uint8_t *a, const uint16_t l);
static bool validateEepromMD5(uint64_t ver, uint32_t eepromstart, uint32_t flen) {
#define CHUNK_SIZE 512
uint8_t chunk[CHUNK_SIZE];
MD5Context ctx;
md5Init(&ctx);
// Open the executable itself for reading
for (uint32_t offset = 0; offset < flen; offset += CHUNK_SIZE) {
uint32_t len = flen - offset;
if (len > CHUNK_SIZE) len = CHUNK_SIZE;
FLASH_Read(FLASH_NORMAL_READ, eepromstart + offset, chunk, len);
// eepromRead(eepromstart + offset, chunk, 512);
md5Update(&ctx, chunk, len);
}
// Retrieve the final hash
md5Finalize(&ctx);
bool isValid = ver == *((uint64_t *)ctx.digest);
if (!isValid) {
printf("MD5 failed check! This is what we should get:\n");
dump((const uint8_t *)&(ver), 8);
printf("This is what we got:\n");
dump(ctx.digest, 16);
} else {
#ifdef DEBUG_PROTO
printf("PROTO: MD5 Pass\n");
#endif
}
#ifdef DEBUG_DONTVALIDATEPROTO
return true;
#else
return isValid;
#endif
}
#include "../common/oepl-protocol.cpp"

View File

@@ -0,0 +1,10 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "settings.h"
#define PERSISTENTVAR __attribute__((section(".aonshadow")))
#include "../common/oepl-protocol.h"

View File

@@ -2,9 +2,11 @@
#include <stdlib.h>
#include <string.h>
#include <vector>
#include "settings.h"
extern "C" {
#include "mz100/mz100_flash.h"
#include "mz100/printf.h"
#include "mz100/util.h"
}
// #pragma pack(1)
@@ -14,9 +16,10 @@ extern "C" {
extern "C" {
__attribute__((section(".aonshadow"))) uint32_t fsEntry;
__attribute__((section(".aonshadow"))) uint32_t fsEnd;
extern void dump(const uint8_t *a, const uint16_t l);
}
extern void dump(const uint8_t *a, const uint16_t l);
OEPLFs oeplfs;
OEPLFs *fs = &oeplfs;
@@ -41,7 +44,9 @@ OEPLFs::~OEPLFs() {
}
uint32_t OEPLFs::findEntry() {
#ifdef DEBUG_FS
printf("FS: Trying to find OEPL FS...\n");
#endif
uint8_t *scan = (uint8_t *)malloc(1024);
uint32_t offset = 0;
// scan flash with some overlap, to ensure the entire string is in the buffer at some point
@@ -69,7 +74,9 @@ uint32_t OEPLFs::findEntry() {
}
if (offset) {
#ifdef DEBUG_FS
printf("FS: Found at 0x%08X\n", offset);
#endif
} else {
printf("FS: Not found. Did you forget to add it?\n");
FLASH_Read(FLASH_FAST_READ_QUAD_OUT, 0x109C0, scan, 1024);
@@ -79,6 +86,40 @@ uint32_t OEPLFs::findEntry() {
return offset;
}
void OEPLFs::deleteFile(char *name) {
// get file list inside of the vector
uint8_t *buffer = (uint8_t *)malloc(1024);
FLASH_Read(FLASH_FAST_READ_QUAD_OUT, fsEntry, buffer, 1024);
bool firstFile = true;
uint8_t *fatEnd = nullptr;
uint8_t *curFileP = buffer;
curFileP += 11; // set to begin file table
while (1) {
OEPLFSFile *file;
file = new OEPLFSFile;
memcpy((void *)file, curFileP, sizeof(OEPLFSFile));
if (firstFile) {
firstFile = false;
fatEnd = buffer + file->offset - 1;
}
if (strncmp(name, file->name, FILENAME_LENGTH) == 0) {
char overwriteName[FILENAME_LENGTH];
memset(overwriteName, 0x00, FILENAME_LENGTH);
FLASH_Write(FLASH_PROGRAM_NORMAL, fsEntry + (curFileP - buffer), (uint8_t *)overwriteName, FILENAME_LENGTH);
break;
}
curFileP += sizeof(OEPLFSFile);
if (curFileP > fatEnd) {
break;
}
}
free(buffer);
}
void OEPLFs::populateFiles() {
// get file list inside of the vector
uint8_t *buffer = (uint8_t *)malloc(1024);
@@ -104,8 +145,9 @@ void OEPLFs::populateFiles() {
char tmp[32];
memcpy(tmp, file->name, 32);
tmp[31] = 0x00;
if(!silent)printf("name=%s, size=%u, offset=%u\n", tmp, file->len, file->offset);
#ifdef DEBUG_FS
if (!silent) printf("name=%s, size=%u, offset=%u\n", tmp, file->len, file->offset);
#endif
fsend = file->len + file->offset;
if (curFileP > fatEnd) {
done = true;
@@ -113,6 +155,7 @@ void OEPLFs::populateFiles() {
}
}
fsEnd = fsend + fsEntry;
fsEnd = flashRoundUp(fsEnd);
free(buffer);
}

View File

@@ -38,6 +38,7 @@ class OEPLFs {
OEPLFs();
std::vector<OEPLFSFile*> files;
OEPLFile* getFile(char* name);
void deleteFile(char* name);
void init();
bool isStarted = false;

View File

@@ -6,15 +6,24 @@
// #include <stdio.h>
#include <string.h>
#include "epd_interface.h"
#include "board.h"
#include "mz100/eeprom.h"
#include "main.h"
#include "oepl-protocol.h"
#include "settings.h"
extern "C" {
#include "mz100/eeprom.h"
#include "mz100/mz100_sleep.h"
#include "mz100/printf.h"
#include "screen.h"
#include "syncedproto.h"
#include "mz100/util.h"
#include "zigbee.h"
}
__attribute__((section(".aonshadow"))) uint16_t dataReqAttemptArr[POWER_SAVING_SMOOTHING] = {0}; // Holds the amount of attempts required per data_req/check-in
__attribute__((section(".aonshadow"))) uint8_t dataReqAttemptArrayIndex = 0;
@@ -47,7 +56,7 @@ void setupPortsInitial() {
uint16_t doVoltageReading() {
batteryVoltage = (uint16_t)measureBattery();
if (batteryVoltage < BATTERY_VOLTAGE_MINIMUM) {
if (batteryVoltage < tagSettings.batLowVoltage) {
lowBattery = true;
} else {
lowBattery = false;
@@ -98,6 +107,7 @@ void powerUp(const uint8_t parts) {
}
if (parts & INIT_EPD) {
configSPI(true);
epdSetup();
}
if (parts & INIT_EEPROM) {
configEEPROM(true);
@@ -108,6 +118,9 @@ void powerUp(const uint8_t parts) {
}
void powerDown(const uint8_t parts) {
if(parts & INIT_EPD){
epdEnterSleep();
}
// printf("Power down: %d\r\n", parts);
}

View File

@@ -0,0 +1,159 @@
#include "powermgt.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
// #include <stdio.h>
#include <string.h>
#include "epd_interface.h"
#include "main.h"
#include "oepl-protocol.h"
#include "board.h"
extern "C"{
#include "mz100/eeprom.h"
#include "mz100/mz100_sleep.h"
#include "mz100/printf.h"
#include "screen.h"
#include "mz100/util.h"
#include "zigbee.h"
}
__attribute__((section(".aonshadow"))) uint16_t dataReqAttemptArr[POWER_SAVING_SMOOTHING] = {0}; // Holds the amount of attempts required per data_req/check-in
__attribute__((section(".aonshadow"))) uint8_t dataReqAttemptArrayIndex = 0;
__attribute__((section(".aonshadow"))) uint8_t dataReqLastAttempt = 0;
__attribute__((section(".aonshadow"))) uint16_t nextCheckInFromAP = 0;
__attribute__((section(".aonshadow"))) uint8_t wakeUpReason = 0;
__attribute__((section(".aonshadow"))) uint8_t scanAttempts = 0;
__attribute__((section(".aonshadow"))) int8_t temperature = 0;
__attribute__((section(".aonshadow"))) uint16_t batteryVoltage = 0;
__attribute__((section(".aonshadow"))) bool lowBattery = false;
__attribute__((section(".aonshadow"))) uint16_t longDataReqCounter = 0;
__attribute__((section(".aonshadow"))) uint16_t voltageCheckCounter = 0;
__attribute__((section(".aonshadow"))) uint8_t capabilities = 0;
bool spiActive = false;
bool uartActive = false;
bool eepromActive = false;
bool i2cActive = false;
extern int8_t adcSampleTemperature(void); // in degrees C
uint8_t checkButtonOrJig() {
return DETECT_P1_0_NOTHING;
}
void setupPortsInitial() {
}
uint16_t doVoltageReading() {
batteryVoltage = (uint16_t)measureBattery();
if (batteryVoltage < BATTERY_VOLTAGE_MINIMUM) {
lowBattery = true;
} else {
lowBattery = false;
}
return batteryVoltage;
}
void initPowerSaving(const uint16_t initialValue) {
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++) {
dataReqAttemptArr[c] = initialValue;
}
}
static void configSPI(const bool setup) {
spiActive = setup;
}
static void configUART(const bool setup) {
/* if (setup == uartActive)
return;
uartActive = setup;
if (setup)
Serial.begin(115200);
else
Serial.end();*/
}
static void configEEPROM(const bool setup) {
}
static void configI2C(const bool setup) {
}
void powerUp(const uint8_t parts) {
// printf("Power up: %d\r\n", parts);
if (parts & INIT_RADIO) {
radioInit();
// radioRxFilterCfg(mSelfMac, 0x10000, PROTO_PAN_ID);
// radioSetTxPower(10);
if (currentChannel >= 11 && currentChannel <= 27) {
radioSetChannel(currentChannel);
} else {
radioSetChannel(RADIO_FIRST_CHANNEL);
}
}
if (parts & INIT_UART) {
configUART(true);
}
if (parts & INIT_EPD) {
configSPI(true);
epdSetup();
}
if (parts & INIT_EEPROM) {
configEEPROM(true);
}
if (parts & INIT_I2C) {
configI2C(true);
}
}
void powerDown(const uint8_t parts) {
if(parts & INIT_EPD){
epdEnterSleep();
}
// printf("Power down: %d\r\n", parts);
}
void doSleep(const uint32_t t) {
printf("Sleeping for: %d ms\r\n", t);
// sleepForMs(t);
delay(t);
}
uint32_t getNextScanSleep(const bool increment) {
if (increment) {
if (scanAttempts < 255)
scanAttempts++;
}
if (scanAttempts < INTERVAL_1_ATTEMPTS) {
return INTERVAL_1_TIME;
} else if (scanAttempts < (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS)) {
return INTERVAL_2_TIME;
} else {
return INTERVAL_3_TIME;
}
}
void addAverageValue() {
uint16_t curval = INTERVAL_AT_MAX_ATTEMPTS - INTERVAL_BASE;
curval *= dataReqLastAttempt;
curval /= DATA_REQ_MAX_ATTEMPTS;
curval += INTERVAL_BASE;
dataReqAttemptArr[dataReqAttemptArrayIndex % POWER_SAVING_SMOOTHING] = curval;
dataReqAttemptArrayIndex++;
}
uint16_t getNextSleep() {
uint16_t avg = 0;
for (uint8_t c = 0; c < POWER_SAVING_SMOOTHING; c++) {
avg += dataReqAttemptArr[c];
}
avg /= POWER_SAVING_SMOOTHING;
return avg;
}

View File

@@ -29,7 +29,7 @@
#define INTERVAL_AT_MAX_ATTEMPTS 300 // interval (in seconds) (at max attempts) for target average current
#define DATA_REQ_RX_WINDOW_SIZE 5UL // How many milliseconds we should wait for a packet during the data_request.
// If the AP holds a long list of data for tags, it may need a little more time to lookup the mac address
#define DATA_REQ_MAX_ATTEMPTS 3 // How many attempts (at most) we should do to get something back from the AP
#define DATA_REQ_MAX_ATTEMPTS 3 // How many attempts (at most) we should do to get something back from the AP
#define POWER_SAVING_SMOOTHING 8 // How many samples we should use to smooth the data request interval
#define MINIMUM_INTERVAL 45 // IMPORTANT: Minimum interval for check-in; this determines overal battery life!
#define MAXIMUM_PING_ATTEMPTS 3 // How many attempts to discover an AP the tag should do
@@ -37,7 +37,7 @@
#define LONG_DATAREQ_INTERVAL 300 // How often (in seconds, approximately) the tag should do a long datareq (including temperature)
#define VOLTAGE_CHECK_INTERVAL 288 // How often the tag should do a battery voltage check (multiplied by LONG_DATAREQ_INTERVAL)
#define BATTERY_VOLTAGE_MINIMUM 2450 // 2600 or below is the best we can do on the EPD
#define BATTERY_VOLTAGE_MINIMUM 2950 // 2900 or below is the best we can do on the EPD
// power saving when no AP's were found (scanning every X)
#define VOLTAGEREADING_DURING_SCAN_INTERVAL 2 // how often we should read voltages; this is done every scan attempt in interval bracket 3
@@ -55,7 +55,7 @@ extern void powerUp(const uint8_t parts);
extern void powerDown(const uint8_t parts);
extern void initAfterWake();
extern void doSleep(const uint32_t t);
extern void doSleep(const uint32_t t);
extern void addAverageValue();
extern uint16_t getNextSleep();
@@ -65,17 +65,17 @@ extern uint16_t doVoltageReading();
extern uint32_t getNextScanSleep(const bool increment);
extern void initPowerSaving(const uint16_t initialValue);
extern uint8_t wakeUpReason;
extern uint8_t wakeUpReason;
extern __attribute__((section(".aonshadow"))) uint8_t capabilities;
extern __attribute__((section(".aonshadow"))) uint8_t capabilities;
extern uint16_t nextCheckInFromAP;
extern __attribute__((section(".aonshadow"))) uint8_t dataReqLastAttempt;
extern __attribute__((section(".aonshadow"))) int8_t temperature;
extern __attribute__((section(".aonshadow"))) uint16_t batteryVoltage;
extern __attribute__((section(".aonshadow"))) bool lowBattery;
extern __attribute__((section(".aonshadow"))) uint8_t scanAttempts;
extern __attribute__((section(".aonshadow"))) uint16_t longDataReqCounter;
extern __attribute__((section(".aonshadow"))) uint16_t voltageCheckCounter;
extern uint16_t nextCheckInFromAP;
extern __attribute__((section(".aonshadow"))) uint8_t dataReqLastAttempt;
extern __attribute__((section(".aonshadow"))) int8_t temperature;
extern __attribute__((section(".aonshadow"))) uint16_t batteryVoltage;
extern __attribute__((section(".aonshadow"))) bool lowBattery;
extern __attribute__((section(".aonshadow"))) uint8_t scanAttempts;
extern __attribute__((section(".aonshadow"))) uint16_t longDataReqCounter;
extern __attribute__((section(".aonshadow"))) uint16_t voltageCheckCounter;
#endif

View File

@@ -1,28 +0,0 @@
#include "settings.h"
#include "proto.h"
#include <string.h>
#include "mz100/eeprom.h"
#include "mz100/util.h"
#include "mz100/mz100_flash.h"
#include "powermgt.h"
__attribute__((section(".aonshadow"))) struct tagsettings tagSettings = {0};
extern uint8_t blockXferBuffer[];
uint8_t* infopageTempBuffer = 1024 + blockXferBuffer;
void loadDefaultSettings() {
tagSettings.settingsVer = SETTINGS_STRUCT_VERSION;
tagSettings.enableFastBoot = DEFAULT_SETTING_FASTBOOT;
tagSettings.enableRFWake = DEFAULT_SETTING_RFWAKE;
tagSettings.enableTagRoaming = DEFAULT_SETTING_TAGROAMING;
tagSettings.enableScanForAPAfterTimeout = DEFAULT_SETTING_SCANFORAP;
tagSettings.enableLowBatSymbol = DEFAULT_SETTING_LOWBATSYMBOL;
tagSettings.enableNoRFSymbol = DEFAULT_SETTING_NORFSYMBOL;
tagSettings.customMode = 0;
tagSettings.fastBootCapabilities = 0;
tagSettings.minimumCheckInTime = INTERVAL_BASE;
tagSettings.fixedChannel = 0;
tagSettings.batLowVoltage = BATTERY_VOLTAGE_MINIMUM;
}

View File

@@ -0,0 +1,107 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include "settings.h"
#include "proto.h"
extern "C" {
#include <string.h>
#include "mz100/eeprom.h"
#include "mz100/util.h"
#include "mz100/mz100_flash.h"
#include "powermgt.h"
#include "mz100/printf.h"
}
#include "oepl_fs.h"
__attribute__((section(".aonshadow"))) struct tagsettings tagSettings = {0};
__attribute__((section(".aonshadow"))) struct tagHardwareProfile tagProfile = {0};
void loadDefaultSettings() {
tagSettings.settingsVer = SETTINGS_STRUCT_VERSION;
tagSettings.enableFastBoot = DEFAULT_SETTING_FASTBOOT;
tagSettings.enableRFWake = DEFAULT_SETTING_RFWAKE;
tagSettings.enableTagRoaming = DEFAULT_SETTING_TAGROAMING;
tagSettings.enableScanForAPAfterTimeout = DEFAULT_SETTING_SCANFORAP;
tagSettings.enableLowBatSymbol = DEFAULT_SETTING_LOWBATSYMBOL;
tagSettings.enableNoRFSymbol = DEFAULT_SETTING_NORFSYMBOL;
tagSettings.customMode = 0;
tagSettings.fastBootCapabilities = 0;
tagSettings.minimumCheckInTime = INTERVAL_BASE;
tagSettings.fixedChannel = 0;
tagSettings.batLowVoltage = BATTERY_VOLTAGE_MINIMUM;
}
#define SETTINGS_OFFSET 8
#define TAGPROFILE_OFFSET 32
void invalidateSettings() {
uint64_t buffer = 0x5555555555555555ull;
FLASH_Write(FLASH_PROGRAM_NORMAL, EEPROM_SETTINGS_AREA_START, (uint8_t*)&buffer, 8);
}
static bool compareSettings() {
// check if the values are already the same, to ensure we don't write the same values to flash
uint8_t buffer[256];
uint64_t magic;
FLASH_Read(FLASH_NORMAL_READ, EEPROM_SETTINGS_AREA_START, (uint8_t*)&magic, 8);
if (magic != MAGIC_NUMBER_SETTINGS) {
return false;
}
FLASH_Read(FLASH_NORMAL_READ, EEPROM_SETTINGS_AREA_START + SETTINGS_OFFSET, buffer, sizeof(struct tagsettings) + 64);
if (memcmp((void*)buffer, (void*)&tagSettings, sizeof(struct tagsettings)) != 0) {
return false;
}
FLASH_Read(FLASH_NORMAL_READ, EEPROM_SETTINGS_AREA_START + TAGPROFILE_OFFSET, buffer, sizeof(struct tagHardwareProfile));
if (memcmp((void*)buffer, (void*)&tagProfile, sizeof(struct tagHardwareProfile)) != 0) {
return false;
}
#ifdef DEBUG_SETTINGS
printf("SETTINGS: Settings/profile match, not saving.\n");
#endif
return true;
}
void writeSettings() {
if (compareSettings()) return;
#ifdef DEBUG_SETTINGS
printf("SETTINGS: Writing settings\n");
#endif
FLASH_Erase(EEPROM_SETTINGS_AREA_START, EEPROM_SETTINGS_AREA_START + 4095);
FLASH_Write(FLASH_PROGRAM_NORMAL, EEPROM_SETTINGS_AREA_START + SETTINGS_OFFSET, (uint8_t*)&tagSettings, sizeof(struct tagsettings));
FLASH_Write(FLASH_PROGRAM_NORMAL, EEPROM_SETTINGS_AREA_START + TAGPROFILE_OFFSET, (uint8_t*)&tagProfile, sizeof(struct tagHardwareProfile));
uint64_t magic = MAGIC_NUMBER_SETTINGS;
FLASH_Write(FLASH_PROGRAM_NORMAL, EEPROM_SETTINGS_AREA_START, (uint8_t*)&magic, 8);
}
bool loadSettings() {
uint64_t magic;
FLASH_Read(FLASH_NORMAL_READ, EEPROM_SETTINGS_AREA_START, (uint8_t*)&magic, 8);
if (magic == MAGIC_NUMBER_SETTINGS) {
#ifdef DEBUG_SETTINGS
printf("SETTINGS: Succesfully loaded settings\n");
#endif
FLASH_Read(FLASH_NORMAL_READ, EEPROM_SETTINGS_AREA_START + SETTINGS_OFFSET, (uint8_t*)&tagSettings, sizeof(struct tagsettings));
FLASH_Read(FLASH_NORMAL_READ, EEPROM_SETTINGS_AREA_START + TAGPROFILE_OFFSET, (uint8_t*)&tagProfile, sizeof(struct tagHardwareProfile));
return true;
} else {
#ifdef DEBUG_SETTINGS
printf("SETTINGS: Default settings loaded\n");
#endif
loadDefaultSettings();
return false;
}
}
bool loadProfileFromFile(char* filename) {
OEPLFile* file = fs->getFile(filename);
if (!file) {
return false;
}
file->getBlock(0, (uint8_t*)&tagProfile, sizeof(struct tagHardwareProfile));
writeSettings();
return true;
}

View File

@@ -3,16 +3,27 @@
#include <stdint.h>
#define FW_VERSION 0x0027 // version number (max 2.5.5 :) )
#define FW_VERSION_SUFFIX "-75" // suffix, like -RC1 or whatever.
// #define DEBUGBLOCKS // uncomment to enable extra debug information on the block transfers
// #define PRINT_LUT // uncomment if you want the tag to print the LUT for the current temperature bracket
#define FW_VERSION 0x0027 // version number (max 2.5.5 :) )
#define FW_VERSION_SUFFIX "-zlib" // suffix, like -RC1 or whatever.
#define DEBUG_EPD
#define DEBUG_FS
//#define DEBUGBLOCKS // uncomment to enable extra debug information on the block transfers
//#define PRINT_LUT // uncomment if you want the tag to print the LUT for the current temperature bracket
//#define DEBUG_EPD
//#define DEBUG_FS
//#define DEBUG_COMPRESSION
//#define DEBUG_PROTO
//#define DEBUG_SETTINGS
//#define DEBUG_DONTVALIDATEPROTO
#if defined(DEBUG_SETTINGS) || defined(DEBUG_EPD) || defined(DEBUGBLOCKS) || defined(DEBUG_PROTO) || defined(DEBUG_COMPRESSION) || defined(DEBUG_FS)
#define DEBUG_BUILD
#define DEBUG_COMPRESSION
#endif
#define SETTINGS_STRUCT_VERSION 0x01
@@ -24,10 +35,17 @@
#define DEFAULT_SETTING_LOWBATSYMBOL 1
#define DEFAULT_SETTING_NORFSYMBOL 1
extern __attribute__((section(".aonshadow")))struct tagsettings tagSettings;
#define MAGIC_NUMBER_SETTINGS (0xD34DBEEFD0D0CAFEull)
#include "tagprofile_struct.h"
extern __attribute__((section(".aonshadow"))) struct tagsettings tagSettings;
extern __attribute__((section(".aonshadow"))) struct tagHardwareProfile tagProfile;
void invalidateSettings();
void loadDefaultSettings();
void writeSettings();
void loadSettings();
bool loadSettings();
void loadSettingsFromBuffer(uint8_t* p);
bool loadProfileFromFile(char* filename);
#endif

View File

@@ -1,839 +0,0 @@
#include "syncedproto.h"
#include "board.h"
#include "comms.h"
#include "mz100/eeprom.h"
#include "main.h"
#include "mz100/mz100_sleep.h"
#include "powermgt.h"
#include "mz100/printf.h"
#include "proto.h"
#include "mz100/timer.h"
#include "mz100/util.h"
#include "mz100/mz100_flash.h"
#include "zigbee.h"
#include "md5.h"
// download-stuff
uint8_t blockXferBuffer[BLOCK_XFER_BUFFER_SIZE] = {0};
__attribute__((section(".aonshadow"))) struct blockRequest curBlock = {0}; // used by the block-requester, contains the next request that we'll send
__attribute__((section(".aonshadow"))) struct AvailDataInfo xferDataInfo = {0}; // last 'AvailDataInfo' we received from the AP
bool requestPartialBlock = false; // if we should ask the AP to get this block from the host or not
#define BLOCK_TRANSFER_ATTEMPTS 10
__attribute__((section(".aonshadow"))) uint8_t prevImgSlot = 0xFF;
__attribute__((section(".aonshadow"))) uint8_t curImgSlot = 0xFF;
__attribute__((section(".aonshadow"))) static uint32_t curHighSlotId = 0;
__attribute__((section(".aonshadow"))) static uint8_t nextImgSlot = 0;
__attribute__((section(".aonshadow"))) static uint8_t imgSlots = 0;
__attribute__((section(".aonshadow"))) uint8_t drawWithLut = 0;
// stuff we need to keep track of related to the network/AP
uint8_t APmac[8] = {0};
uint16_t APsrcPan = 0;
__attribute__((section(".aonshadow"))) uint8_t mSelfMac[8] = {0};
__attribute__((section(".aonshadow"))) static uint8_t seq = 0;
__attribute__((section(".aonshadow"))) volatile uint8_t currentChannel = 0;
// buffer we use to prepare/read packets
static uint8_t inBuffer[128] = {0};
static uint8_t outBuffer[128] = {0};
// #define DEBUGBLOCKS 1
// from drawing.cpp
extern void drawImageAtAddress(uint32_t addr, uint8_t lut);
// tools
static uint8_t getPacketType(const void *buffer) {
const struct MacFcs *fcs = buffer;
if ((fcs->frameType == 1) && (fcs->destAddrType == 2) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 0)) {
// broadcast frame
uint8_t type = ((uint8_t *)buffer)[sizeof(struct MacFrameBcast)];
return type;
} else if ((fcs->frameType == 1) && (fcs->destAddrType == 3) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 1)) {
// normal frame
uint8_t type = ((uint8_t *)buffer)[sizeof(struct MacFrameNormal)];
return type;
}
return 0;
}
static bool pktIsUnicast(const void *buffer) {
const struct MacFcs *fcs = buffer;
if ((fcs->frameType == 1) && (fcs->destAddrType == 2) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 0)) {
return false;
} else if ((fcs->frameType == 1) && (fcs->destAddrType == 3) && (fcs->srcAddrType == 3) && (fcs->panIdCompressed == 1)) {
// normal frame
return true;
}
// unknown type...
return false;
}
void dump(const uint8_t *a, const uint16_t l) {
printf("\n ");
#define ROWS 16
for (uint8_t c = 0; c < ROWS; c++) {
printf(" %02X", c);
}
printf("\n--------");
for (uint8_t c = 0; c < ROWS; c++) {
printf("---");
}
for (uint16_t c = 0; c < l; c++) {
if ((c % ROWS) == 0) {
printf("\n0x%04X | ", c);
}
printf("%02X ", a[c]);
}
printf("\n--------");
for (uint8_t c = 0; c < ROWS; c++) {
printf("---");
}
printf("\n");
}
static bool checkCRC(const void *p, const uint8_t len) {
uint8_t total = 0;
for (uint8_t c = 1; c < len; c++) {
total += ((uint8_t *)p)[c];
}
// printf("CRC: rx %d, calc %d\n", ((uint8_t *)p)[0], total);
return ((uint8_t *)p)[0] == total;
}
static void addCRC(void *p, const uint8_t len) {
uint8_t total = 0;
for (uint8_t c = 1; c < len; c++) {
total += ((uint8_t *)p)[c];
}
((uint8_t *)p)[0] = total;
}
// radio stuff
static void sendPing() {
struct MacFrameBcast *txframe = (struct MacFrameBcast *)(outBuffer + 1);
memset(outBuffer, 0, sizeof(struct MacFrameBcast) + 2 + 4);
outBuffer[0] = sizeof(struct MacFrameBcast) + 1 + 2;
outBuffer[sizeof(struct MacFrameBcast) + 1] = PKT_PING;
memcpy(txframe->src, mSelfMac, 8);
txframe->fcs.frameType = 1;
txframe->fcs.ackReqd = 1;
txframe->fcs.destAddrType = 2;
txframe->fcs.srcAddrType = 3;
txframe->seq = seq++;
txframe->dstPan = PROTO_PAN_ID;
txframe->dstAddr = 0xFFFF;
txframe->srcPan = PROTO_PAN_ID;
commsTxNoCpy(outBuffer);
}
uint8_t detectAP(const uint8_t channel) {
uint32_t t;
radioRxEnable(false);
radioSetChannel(channel);
radioRxFlush();
radioRxEnable(true);
for (uint8_t c = 1; c <= MAXIMUM_PING_ATTEMPTS; c++) {
sendPing();
t = timerGet() + (TIMER_TICKS_PER_MSEC * 5);
while (timerGet() < t) {
int8_t ret = commsRxUnenc(inBuffer);
if (ret > 1) {
if ((inBuffer[sizeof(struct MacFrameNormal) + 1] == channel) && (getPacketType(inBuffer) == PKT_PONG)) {
if (pktIsUnicast(inBuffer)) {
// dump(inBuffer,32);
struct MacFrameNormal *f = (struct MacFrameNormal *)inBuffer;
memcpy(APmac, f->src, 8);
APsrcPan = f->pan;
return c;
}
}
}
timerDelay(TIMER_TICKS_PER_MSEC * 2);
}
}
return 0;
}
// data xfer stuff
static void sendShortAvailDataReq() {
struct MacFrameBcast *txframe = (struct MacFrameBcast *)(outBuffer + 1);
outBuffer[0] = sizeof(struct MacFrameBcast) + 1 + 2;
outBuffer[sizeof(struct MacFrameBcast) + 1] = PKT_AVAIL_DATA_SHORTREQ;
memcpy(txframe->src, mSelfMac, 8);
outBuffer[1] = 0x21;
outBuffer[2] = 0xC8; // quickly set txframe fcs structure for broadcast packet
txframe->seq = seq++;
txframe->dstPan = PROTO_PAN_ID;
txframe->dstAddr = 0xFFFF;
txframe->srcPan = PROTO_PAN_ID;
commsTxNoCpy(outBuffer);
}
static void sendAvailDataReq() {
struct MacFrameBcast *txframe = (struct MacFrameBcast *)(outBuffer + 1);
memset(outBuffer, 0, sizeof(struct MacFrameBcast) + sizeof(struct AvailDataReq) + 2 + 4);
struct AvailDataReq *availreq = (struct AvailDataReq *)(outBuffer + 2 + sizeof(struct MacFrameBcast));
outBuffer[0] = sizeof(struct MacFrameBcast) + sizeof(struct AvailDataReq) + 2 + 2;
outBuffer[sizeof(struct MacFrameBcast) + 1] = PKT_AVAIL_DATA_REQ;
memcpy(txframe->src, mSelfMac, 8);
txframe->fcs.frameType = 1;
txframe->fcs.ackReqd = 1;
txframe->fcs.destAddrType = 2;
txframe->fcs.srcAddrType = 3;
txframe->seq = seq++;
txframe->dstPan = PROTO_PAN_ID;
txframe->dstAddr = 0xFFFF;
txframe->srcPan = PROTO_PAN_ID;
// TODO: send some (more) meaningful data
availreq->hwType = 5;
availreq->wakeupReason = wakeUpReason;
availreq->lastPacketRSSI = mLastRSSI;
availreq->lastPacketLQI = mLastLqi;
availreq->temperature = temperature;
availreq->batteryMv = batteryVoltage;
availreq->capabilities = capabilities;
availreq->tagSoftwareVersion = FW_VERSION;
addCRC(availreq, sizeof(struct AvailDataReq));
commsTxNoCpy(outBuffer);
}
struct AvailDataInfo *getAvailDataInfo() {
radioRxEnable(true);
uint32_t t;
for (uint8_t c = 0; c < DATA_REQ_MAX_ATTEMPTS; c++) {
sendAvailDataReq();
t = timerGet() + (TIMER_TICKS_PER_MSEC * (DATA_REQ_RX_WINDOW_SIZE + 2));
while (timerGet() < t) {
int8_t ret = commsRxUnenc(inBuffer);
if (ret > 1) {
if (getPacketType(inBuffer) == PKT_AVAIL_DATA_INFO) {
if (checkCRC(inBuffer + sizeof(struct MacFrameNormal) + 1, sizeof(struct AvailDataInfo))) {
struct MacFrameNormal *f = (struct MacFrameNormal *)inBuffer;
memcpy(APmac, f->src, 8);
APsrcPan = f->pan;
dataReqLastAttempt = c;
return (struct AvailDataInfo *)(inBuffer + sizeof(struct MacFrameNormal) + 1);
}
}
}
}
}
dataReqLastAttempt = DATA_REQ_MAX_ATTEMPTS;
return NULL;
}
struct AvailDataInfo *getShortAvailDataInfo() {
radioRxEnable(true);
uint32_t t;
for (uint8_t c = 0; c < DATA_REQ_MAX_ATTEMPTS; c++) {
sendShortAvailDataReq();
// sendAvailDataReq();
t = timerGet() + (TIMER_TICKS_PER_MSEC * 25);
while (timerGet() < t) {
int8_t ret = commsRxUnenc(inBuffer);
if (ret > 1) {
if (getPacketType(inBuffer) == PKT_AVAIL_DATA_INFO) {
if (checkCRC(inBuffer + sizeof(struct MacFrameNormal) + 1, sizeof(struct AvailDataInfo))) {
struct MacFrameNormal *f = (struct MacFrameNormal *)inBuffer;
memcpy(APmac, f->src, 8);
APsrcPan = f->pan;
dataReqLastAttempt = c;
printf("%d", dataReqLastAttempt);
return (struct AvailDataInfo *)(inBuffer + sizeof(struct MacFrameNormal) + 1);
}
}
}
}
}
dataReqLastAttempt = DATA_REQ_MAX_ATTEMPTS;
return NULL;
}
static bool processBlockPart(const struct blockPart *bp) {
uint16_t start = bp->blockPart * BLOCK_PART_DATA_SIZE;
uint16_t size = BLOCK_PART_DATA_SIZE;
// validate if it's okay to copy data
if (bp->blockId != curBlock.blockId) {
// printf("got a packet for block %02X\n", bp->blockId);
return false;
}
if (start >= (sizeof(blockXferBuffer) - 1))
return false;
if (bp->blockPart > BLOCK_MAX_PARTS)
return false;
if ((start + size) > sizeof(blockXferBuffer)) {
size = sizeof(blockXferBuffer) - start;
}
if (checkCRC(bp, sizeof(struct blockPart) + BLOCK_PART_DATA_SIZE)) {
// copy block data to buffer
memcpy((void *)(blockXferBuffer + start), (const void *)bp->data, size);
// we don't need this block anymore, set bit to 0 so we don't request it again
curBlock.requestedParts[bp->blockPart / 8] &= ~(1 << (bp->blockPart % 8));
return true;
} else {
return false;
}
}
static bool blockRxLoop(const uint32_t timeout) {
uint32_t t;
bool success = false;
radioRxEnable(true);
t = timerGet() + (TIMER_TICKS_PER_MSEC * (timeout + 20));
while (timerGet() < t) {
int8_t ret = commsRxUnenc(inBuffer);
if (ret > 1) {
if (getPacketType(inBuffer) == PKT_BLOCK_PART) {
struct blockPart *bp = (struct blockPart *)(inBuffer + sizeof(struct MacFrameNormal) + 1);
success = processBlockPart(bp);
}
}
}
radioRxEnable(false);
radioRxFlush();
return success;
}
static struct blockRequestAck *continueToRX() {
struct blockRequestAck *ack = (struct blockRequestAck *)(inBuffer + sizeof(struct MacFrameNormal) + 1);
ack->pleaseWaitMs = 0;
return ack;
}
static void sendBlockRequest() {
memset(outBuffer, 0, sizeof(struct MacFrameNormal) + sizeof(struct blockRequest) + 2 + 2);
struct MacFrameNormal *f = (struct MacFrameNormal *)(outBuffer + 1);
struct blockRequest *blockreq = (struct blockRequest *)(outBuffer + 2 + sizeof(struct MacFrameNormal));
outBuffer[0] = sizeof(struct MacFrameNormal) + sizeof(struct blockRequest) + 2 + 2;
if (requestPartialBlock) {
;
outBuffer[sizeof(struct MacFrameNormal) + 1] = PKT_BLOCK_PARTIAL_REQUEST;
} else {
outBuffer[sizeof(struct MacFrameNormal) + 1] = PKT_BLOCK_REQUEST;
}
memcpy(f->src, mSelfMac, 8);
memcpy(f->dst, APmac, 8);
f->fcs.frameType = 1;
f->fcs.secure = 0;
f->fcs.framePending = 0;
f->fcs.ackReqd = 0;
f->fcs.panIdCompressed = 1;
f->fcs.destAddrType = 3;
f->fcs.frameVer = 0;
f->fcs.srcAddrType = 3;
f->seq = seq++;
f->pan = APsrcPan;
memcpy(blockreq, &curBlock, sizeof(struct blockRequest));
// printf("req ver: %02X%02X%02X%02X%02X%02X%02X%02X\n", ((uint8_t*)&blockreq->ver)[0],((uint8_t*)&blockreq->ver)[1],((uint8_t*)&blockreq->ver)[2],((uint8_t*)&blockreq->ver)[3],((uint8_t*)&blockreq->ver)[4],((uint8_t*)&blockreq->ver)[5],((uint8_t*)&blockreq->ver)[6],((uint8_t*)&blockreq->ver)[7]);
addCRC(blockreq, sizeof(struct blockRequest));
commsTxNoCpy(outBuffer);
}
static struct blockRequestAck *performBlockRequest() {
uint32_t t;
radioRxEnable(true);
radioRxFlush();
for (uint8_t c = 0; c < 30; c++) {
sendBlockRequest();
t = timerGet() + (TIMER_TICKS_PER_MSEC * (7UL + c / 10));
do {
int8_t ret = commsRxUnenc(inBuffer);
if (ret > 1) {
switch (getPacketType(inBuffer)) {
case PKT_BLOCK_REQUEST_ACK:
if (checkCRC((inBuffer + sizeof(struct MacFrameNormal) + 1), sizeof(struct blockRequestAck)))
return (struct blockRequestAck *)(inBuffer + sizeof(struct MacFrameNormal) + 1);
break;
case PKT_BLOCK_PART:
// block already started while we were waiting for a get block reply
// printf("!");
// processBlockPart((struct blockPart *)(inBuffer + sizeof(struct MacFrameNormal) + 1));
return continueToRX();
break;
case PKT_CANCEL_XFER:
return NULL;
default:
printf("pkt w/type %02X\n", getPacketType(inBuffer));
break;
}
}
} while (timerGet() < t);
}
return continueToRX();
// return NULL;
}
static void sendXferCompletePacket() {
memset(outBuffer, 0, sizeof(struct MacFrameNormal) + 2 + 4);
struct MacFrameNormal *f = (struct MacFrameNormal *)(outBuffer + 1);
outBuffer[0] = sizeof(struct MacFrameNormal) + 2 + 2;
outBuffer[sizeof(struct MacFrameNormal) + 1] = PKT_XFER_COMPLETE;
memcpy(f->src, mSelfMac, 8);
memcpy(f->dst, APmac, 8);
f->fcs.frameType = 1;
f->fcs.secure = 0;
f->fcs.framePending = 0;
f->fcs.ackReqd = 0;
f->fcs.panIdCompressed = 1;
f->fcs.destAddrType = 3;
f->fcs.frameVer = 0;
f->fcs.srcAddrType = 3;
f->pan = APsrcPan;
f->seq = seq++;
commsTxNoCpy(outBuffer);
}
static void sendXferComplete() {
radioRxEnable(true);
for (uint8_t c = 0; c < 16; c++) {
sendXferCompletePacket();
uint32_t start = timerGet();
while ((timerGet() - start) < (TIMER_TICKS_PER_MSEC * 6UL)) {
int8_t ret = commsRxUnenc(inBuffer);
if (ret > 1) {
if (getPacketType(inBuffer) == PKT_XFER_COMPLETE_ACK) {
printf("XFC ACK\n");
return;
}
}
}
}
printf("XFC NACK!\n");
return;
}
static bool validateBlockData() {
struct blockData *bd = (struct blockData *)blockXferBuffer;
// printf("expected len = %04X, checksum=%04X\n", bd->size, bd->checksum);
uint16_t t = 0;
for (uint16_t c = 0; c < bd->size; c++) {
t += bd->data[c];
}
return bd->checksum == t;
}
// EEprom related stuff
static bool validateEepromMD5(uint64_t ver, uint32_t eepromstart, uint32_t flen) {
#define CHUNK_SIZE 512
uint8_t chunk[CHUNK_SIZE];
MD5Context ctx;
md5Init(&ctx);
// Open the executable itself for reading
for (uint32_t offset = 0; offset < flen; offset += CHUNK_SIZE) {
uint32_t len = flen - offset;
if (len > CHUNK_SIZE) len = CHUNK_SIZE;
FLASH_Read(FLASH_FAST_READ_QUAD_OUT, eepromstart + offset, chunk, len);
eepromRead(eepromstart + offset, chunk, 512);
md5Update(&ctx, chunk, len);
}
// Retrieve the final hash
md5Finalize(&ctx);
bool isValid = ver == *((uint64_t *)ctx.digest);
if (!isValid) {
printf("MD5 failed check! This is what we should get:\n");
dump((const uint8_t *)&(xferDataInfo.dataVer), 8);
printf("This is what we got:\n");
dump(ctx.digest, 16);
}
return isValid;
}
static uint32_t getAddressForSlot(const uint8_t s) {
return EEPROM_IMG_START + (EEPROM_IMG_EACH * s);
}
static void getNumSlots() {
printf("Checking slots\n");
imgSlots = 1;
/*uint32_t eeSize = eepromGetSize();
uint16_t nSlots = (eeSize - EEPROM_IMG_START) / (EEPROM_IMG_EACH >> 8) >> 8;
if (eeSize < EEPROM_IMG_START || !nSlots)
{
printf("eeprom is too small\n");
while (1)
;
}
else if (nSlots >> 8)
{
printf("eeprom is too big, some will be unused\n");
imgSlots = 254;
}
else
imgSlots = nSlots;*/
printf("Got %i nr of slots\n", imgSlots);
}
static uint8_t findSlot(const uint8_t *ver) {
// return 0xFF; // remove me! This forces the tag to re-download each and every upload without checking if it's already in the eeprom somewhere
uint32_t markerValid = EEPROM_IMG_VALID;
for (uint8_t c = 0; c < imgSlots; c++) {
struct EepromImageHeader *eih = (struct EepromImageHeader *)blockXferBuffer;
eepromRead(getAddressForSlot(c), eih, sizeof(struct EepromImageHeader));
if (!memcmp(&eih->validMarker, &markerValid, 4)) {
if (!memcmp(&eih->version, (void *)ver, 8)) {
return c;
}
}
}
return 0xFF;
}
static void eraseUpdateBlock() {
qspiEraseRange(EEPROM_UPDATE_START, EEPROM_UPDATE_LEN);
}
static void saveUpdateBlockData(uint8_t blockId) {
printf("EEPROM writing UpdateBlock %i\n", blockId);
if (!eepromWrite(EEPROM_UPDATE_START + (blockId * BLOCK_DATA_SIZE), blockXferBuffer + sizeof(struct blockData), BLOCK_DATA_SIZE))
printf("EEPROM write failed\n");
}
static void saveImgBlockData(const uint8_t imgSlot, const uint8_t blockId) {
printf("EEPROM writing Slot: %i ImageBlock %i\n", imgSlot, blockId);
uint32_t length = EEPROM_IMG_EACH - (sizeof(struct EepromImageHeader) + (blockId * BLOCK_DATA_SIZE));
if (length > 4096)
length = 4096;
if (!eepromWrite(getAddressForSlot(imgSlot) + sizeof(struct EepromImageHeader) + (blockId * BLOCK_DATA_SIZE), blockXferBuffer + sizeof(struct blockData), length))
printf("EEPROM write failed\n");
}
void drawImageFromEeprom(const uint8_t imgSlot) {
drawImageAtAddress(getAddressForSlot(imgSlot), drawWithLut);
drawWithLut = 0; // default back to the regular ol' stock/OTP LUT
}
static uint32_t getHighSlotId() {
uint32_t temp = 0;
/*uint32_t markerValid = EEPROM_IMG_VALID;
for (uint8_t c = 0; c < imgSlots; c++)
{
struct EepromImageHeader *eih = (struct EepromImageHeader *)blockXferBuffer;
eepromRead(getAddressForSlot(c), eih, sizeof(struct EepromImageHeader));
if (!memcmp(&eih->validMarker, &markerValid, 4))
{
if (temp < eih->id)
{
temp = eih->id;
nextImgSlot = c;
}
}
}*/
printf("found high id=%lu in slot %d\n", temp, nextImgSlot);
return temp;
}
static bool getDataBlock(const uint16_t blockSize) {
static uint8_t partsThisBlock = 0;
static uint8_t blockAttempts = 0;
blockAttempts = BLOCK_TRANSFER_ATTEMPTS;
if (blockSize == BLOCK_DATA_SIZE) {
partsThisBlock = BLOCK_MAX_PARTS;
memset(curBlock.requestedParts, 0xFF, BLOCK_REQ_PARTS_BYTES);
} else {
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++) {
curBlock.requestedParts[c / 8] |= (1 << (c % 8));
}
}
requestPartialBlock = false; // this forces the AP to request the block data from the host
while (blockAttempts--) {
#ifndef DEBUGBLOCKS
printf("REQ %d ", curBlock.blockId);
#else
printf("REQ %d[", curBlock.blockId);
for (uint8_t c = 0; c < BLOCK_MAX_PARTS; c++) {
if ((c != 0) && (c % 8 == 0))
printf("][");
if (curBlock.requestedParts[c / 8] & (1 << (c % 8))) {
printf("R");
} else {
printf("_");
}
}
printf("]\n");
#endif
powerUp(INIT_RADIO);
struct blockRequestAck *ack = performBlockRequest();
if (ack == NULL) {
printf("Cancelled request\n");
return false;
}
if (ack->pleaseWaitMs) { // SLEEP - until the AP is ready with the data
timerDelay(TIMER_TICKS_PER_MSEC * ack->pleaseWaitMs);
} else {
// immediately start with the reception of the block data
}
blockRxLoop(270); // BLOCK RX LOOP - receive a block, until the timeout has passed
powerDown(INIT_RADIO);
#ifdef DEBUGBLOCKS
printf("RX %d[", curBlock.blockId);
for (uint8_t c = 0; c < BLOCK_MAX_PARTS; c++) {
if ((c != 0) && (c % 8 == 0))
printf("][");
if (curBlock.requestedParts[c / 8] & (1 << (c % 8))) {
printf(".");
} else {
printf("R");
}
}
printf("]\n");
#endif
// check if we got all the parts we needed, e.g: has the block been completed?
bool blockComplete = true;
for (uint8_t c = 0; c < partsThisBlock; c++) {
if (curBlock.requestedParts[c / 8] & (1 << (c % 8)))
blockComplete = false;
}
if (blockComplete) {
#ifndef DEBUGBLOCKS
printf("- COMPLETE\n");
#endif
if (validateBlockData()) {
// block download complete, validated
return true;
} else {
for (uint8_t c = 0; c < partsThisBlock; c++) {
curBlock.requestedParts[c / 8] |= (1 << (c % 8));
}
requestPartialBlock = false;
printf("blk failed validation!\n");
}
} else {
#ifndef DEBUGBLOCKS
printf("- INCOMPLETE\n");
#endif
// block incomplete, re-request a partial block
requestPartialBlock = true;
}
}
printf("failed getting block\n");
return false;
}
uint16_t dataRequestSize = 0;
uint32_t curXferSize = 0;
static bool downloadFWUpdate(const struct AvailDataInfo *avail) {
// check if we already started the transfer of this information & haven't completed it
if (!memcmp((const void *)&avail->dataVer, (const void *)&xferDataInfo.dataVer, 8) && xferDataInfo.dataSize) {
// looks like we did. We'll carry on where we left off.
} else {
// start, or restart the transfer from 0. Copy data from the AvailDataInfo struct, and the struct intself. This forces a new transfer
curBlock.blockId = 0;
memcpy(&(curBlock.ver), &(avail->dataVer), 8);
curBlock.type = avail->dataType;
memcpy(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
curXferSize = avail->dataSize;
eraseUpdateBlock();
delay(100);
}
while (xferDataInfo.dataSize) {
wdt10s();
if (xferDataInfo.dataSize > BLOCK_DATA_SIZE) {
// more than one block remaining
dataRequestSize = BLOCK_DATA_SIZE;
} else {
// only one block remains
dataRequestSize = xferDataInfo.dataSize;
}
if (getDataBlock(dataRequestSize)) {
// succesfully downloaded datablock, save to eeprom
powerUp(INIT_EEPROM);
saveUpdateBlockData(curBlock.blockId);
powerDown(INIT_EEPROM);
curBlock.blockId++;
xferDataInfo.dataSize -= dataRequestSize;
} else {
// failed to get the block we wanted, we'll stop for now, maybe resume later
return false;
}
}
// no more data, download complete
if (validateEepromMD5(xferDataInfo.dataVer, EEPROM_UPDATE_START, curXferSize)) {
// md5 matches
return true;
} else {
// md5 does not match, invalidate current transfer result, forcing a restart of the transfer
memset((void *)&xferDataInfo, 0, sizeof(struct AvailDataInfo));
return false;
}
}
uint16_t imageSize = 0;
static bool downloadImageDataToEEPROM(const struct AvailDataInfo *avail) {
// check if we already started the transfer of this information & haven't completed it
if (!memcmp((const void *)&avail->dataVer, (const void *)&xferDataInfo.dataVer, 8) && xferDataInfo.dataSize) {
// looks like we did. We'll carry on where we left off.
printf("restarting image download");
curImgSlot = nextImgSlot;
} else {
// go to the next image slot
nextImgSlot++;
if (nextImgSlot >= imgSlots)
nextImgSlot = 0;
curImgSlot = nextImgSlot;
printf("Saving to image slot %d\n", curImgSlot);
drawWithLut = avail->dataTypeArgument;
powerUp(INIT_EEPROM);
uint8_t attempt = 5;
while (attempt--) {
if (eepromErase(getAddressForSlot(curImgSlot), (uint16_t)EEPROM_IMG_EACH))
goto eraseSuccess;
}
NVIC_SystemReset();
eraseSuccess:
printf("new download, writing to slot %d\n", curImgSlot);
// start, or restart the transfer. Copy data from the AvailDataInfo struct, and the struct intself. This forces a new transfer
curBlock.blockId = 0;
memcpy(&(curBlock.ver), &(avail->dataVer), 8);
curBlock.type = avail->dataType;
memcpy(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
imageSize = xferDataInfo.dataSize;
}
while (xferDataInfo.dataSize) {
wdt10s();
if (xferDataInfo.dataSize > BLOCK_DATA_SIZE) {
// more than one block remaining
dataRequestSize = BLOCK_DATA_SIZE;
} else {
// only one block remains
dataRequestSize = xferDataInfo.dataSize;
}
if (getDataBlock(dataRequestSize)) {
// succesfully downloaded datablock, save to eeprom
powerUp(INIT_EEPROM);
#ifdef DEBUGBLOCKS
printf("Saving block %d to slot %d\n", curBlock.blockId, curImgSlot);
#endif
saveImgBlockData(curImgSlot, curBlock.blockId);
powerDown(INIT_EEPROM);
curBlock.blockId++;
xferDataInfo.dataSize -= dataRequestSize;
} else {
// failed to get the block we wanted, we'll stop for now, probably resume later
return false;
}
}
// no more data, download complete
// borrow the blockXferBuffer temporarily
struct EepromImageHeader *eih = (struct EepromImageHeader *)blockXferBuffer;
memcpy(&eih->version, &xferDataInfo.dataVer, 8);
eih->validMarker = EEPROM_IMG_VALID;
eih->id = ++curHighSlotId;
eih->size = imageSize;
eih->dataType = xferDataInfo.dataType;
#ifdef DEBUGBLOCKS
printf("Now writing datatype 0x%02X to slot %d\n", curDataInfo.dataType, curImgSlot);
#endif
if (validateEepromMD5(xferDataInfo.dataVer, getAddressForSlot(curImgSlot) + sizeof(struct EepromImageHeader), imageSize)) {
// md5 matches
eepromWrite(getAddressForSlot(curImgSlot), eih, sizeof(struct EepromImageHeader));
powerDown(INIT_EEPROM);
printf("md5 okay");
return true;
} else {
// md5 does not match, invalidate current transfer result, forcing a restart of the transfer
memset((void *)&xferDataInfo, 0, sizeof(struct AvailDataInfo));
powerDown(INIT_EEPROM);
return false;
}
}
bool processAvailDataInfo(struct AvailDataInfo *avail) {
switch (avail->dataType) {
case DATATYPE_IMG_BMP:
case DATATYPE_IMG_DIFF:
case DATATYPE_IMG_RAW_1BPP:
case DATATYPE_IMG_RAW_2BPP:
case DATATYPE_IMG_ZLIB:
// check if this download is currently displayed or active
if (xferDataInfo.dataSize == 0 && !memcmp((const void *)&avail->dataVer, (const void *)&xferDataInfo.dataVer, 8)) {
// we've downloaded this already, we're guessing it's already displayed
printf("currently shown image, send xfc\n");
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
return true;
}
// check if we've seen this version before
powerUp(INIT_EEPROM);
curImgSlot = findSlot((uint8_t *)&(avail->dataVer));
powerDown(INIT_EEPROM);
if (curImgSlot != 0xFF) {
// found a (complete)valid image slot for this version
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
printf("already seen, drawing from eeprom slot %d\n", curImgSlot);
// mark as completed and draw from EEPROM
memcpy(&xferDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
xferDataInfo.dataSize = 0; // mark as transfer not pending
drawWithLut = avail->dataTypeArgument;
wdt60s();
powerUp(INIT_EPD | INIT_EEPROM);
drawImageFromEeprom(curImgSlot);
powerDown(INIT_EPD | INIT_EEPROM);
return true;
} else {
// not found in cache, prepare to download
printf("downloading to imgslot\n");
drawWithLut = avail->dataTypeArgument;
powerUp(INIT_EEPROM);
if (downloadImageDataToEEPROM(avail)) {
printf("download complete!\n");
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
wdt60s();
powerUp(INIT_EPD | INIT_EEPROM);
drawImageFromEeprom(curImgSlot);
powerDown(INIT_EPD | INIT_EEPROM);
return true;
} else {
powerDown(INIT_EEPROM);
return false;
}
}
break;
case DATATYPE_FW_UPDATE:
powerUp(INIT_EEPROM);
if (downloadFWUpdate(avail)) {
printf("firmware download complete, doing update.\n");
powerUp(INIT_EPD);
// uiPrvFullscreenMsg("Updating", NULL, NULL);
powerUp(INIT_RADIO);
sendXferComplete();
powerDown(INIT_RADIO);
powerUp(INIT_EEPROM);
wdt60s();
applyUpdate();
} else {
return false;
}
break;
case DATATYPE_NFC_URL_DIRECT:
case DATATYPE_NFC_RAW_CONTENT: {
return false;
break;
}
case DATATYPE_CUSTOM_LUT_OTA:
return false;
break;
}
return true;
}
void initializeProto() {
getNumSlots();
curHighSlotId = getHighSlotId();
}

View File

@@ -1,26 +0,0 @@
#pragma once
#include <stdbool.h>
#include <stdint.h>
#include "settings.h"
extern __attribute__((section(".aonshadow"))) uint8_t mSelfMac[];
extern __attribute__((section(".aonshadow"))) volatile uint8_t currentChannel;
extern __attribute__((section(".aonshadow"))) struct blockRequest curBlock; // used by the block-requester, contains the next request that we'll send
extern __attribute__((section(".aonshadow"))) struct AvailDataInfo xferDataInfo; // last 'AvailDataInfo' we received from the AP // __attribute__((section(".aon")))
extern uint8_t APmac[];
extern __attribute__((section(".aonshadow"))) uint8_t curImgSlot;
extern void setupRadio(void);
extern void killRadio(void);
extern struct AvailDataInfo *getAvailDataInfo();
extern struct AvailDataInfo *getShortAvailDataInfo();
extern void drawImageFromEeprom(const uint8_t imgSlot);
extern bool processAvailDataInfo(struct AvailDataInfo *avail);
extern void initializeProto();
extern uint8_t detectAP(const uint8_t channel);

View File

@@ -0,0 +1,11 @@
struct tagHardwareProfile {
uint8_t macAddress[8];
uint16_t xRes;
uint16_t yRes;
uint8_t bpp;
uint8_t controllerType;
uint8_t OEPLType;
uint32_t RC32Mcal;
uint32_t RC32Kcal;
uint8_t reserved[8];
} __attribute__((packed));

View File

@@ -120,7 +120,9 @@ struct __attribute__((packed)) epd_xonlut {
};
void uc8159::epdSetup() {
#ifdef DEBUG_EPD
printf("EPD: Init begin\n");
#endif
initEPDGPIO();
this->epdReset();
epdWrite(EPD_POWER_ON, 0);
@@ -149,10 +151,11 @@ void uc8159::epdSetup() {
this->loadFrameRatePLL(EPDtempBracket);
this->loadTempVCOMDC(EPDtempBracket);
// this->loadTempVSH(EPDtempBracket);
// epdWrite(EPD_POWER_SETTING, 4, 0x37, 0x00, this->vshc, this->vslc); // this doesn't work
// this->loadTempVSH(EPDtempBracket);
// epdWrite(EPD_POWER_SETTING, 4, 0x37, 0x00, this->vshc, this->vslc); // this doesn't work
#ifdef DEBUG_EPD
printf("EPD: Init complete\n");
#endif
}
void uc8159::selectLUT(uint8_t lut) {
@@ -183,7 +186,9 @@ uint8_t uc8159::getTempBracket() {
break;
}
}
#ifdef DEBUG_EPD
printf("EPD: Temp bracket = %d\n", bracket);
#endif
return bracket;
}
void uc8159::loadFrameRatePLL(uint8_t bracket) {
@@ -193,8 +198,10 @@ void uc8159::loadFrameRatePLL(uint8_t bracket) {
eepromReadBlock(0, 25039, plltable, 10);
epdWrite(EPD_SPI_FLASH_CONTROL, 1, 0x00);
pllvalue = plltable[bracket];
#ifdef DEBUG_EPD
printf("loading pll value 0x%02X\n", pllvalue);
pllvalue = 0x3A; // was 0x3C
#endif
// pllvalue = 0x3A; // was 0x3C
epdWrite(EPD_PLL_CONTROL, 1, pllvalue);
}
void uc8159::loadTempVCOMDC(uint8_t bracket) {
@@ -269,6 +276,7 @@ void xonLutSkip(struct epd_xonlut *colorlut, uint8_t skip) {
}
void uc8159::loadLUTSfromEEPROM(uint8_t bracket, bool doRed) {
doRed = false;
for (uint8_t c = EPD_LUT_B; c <= EPD_LUT_R3; c++) {
struct epd_colorlut *colorlut = (struct epd_colorlut *)loadLUT(c, bracket);
@@ -277,9 +285,10 @@ void uc8159::loadLUTSfromEEPROM(uint8_t bracket, bool doRed) {
colorlut->part[0].repeat = 1;
colorLutSkip(colorlut, 2);
if (!doRed) {
colorLutSkip(colorlut, 3);
colorLutSkip(colorlut, 3);
colorLutSkip(colorlut, 3);
colorLutSkip(colorlut, 2);
colorLutSkip(colorlut, 2);
colorLutSkip(colorlut, 2);
colorLutSkip(colorlut, 2);
}
// colorLutSkip(colorlut, 3);
@@ -295,9 +304,10 @@ void uc8159::loadLUTSfromEEPROM(uint8_t bracket, bool doRed) {
vcomLutSkip(vcomlut, 2);
if (!doRed) {
vcomLutSkip(vcomlut, 3);
vcomLutSkip(vcomlut, 3);
vcomLutSkip(vcomlut, 3);
vcomLutSkip(vcomlut, 2);
vcomLutSkip(vcomlut, 2);
vcomLutSkip(vcomlut, 2);
vcomLutSkip(vcomlut, 2);
}
epdBlockWrite(EPD_LUT_VCOM, (uint8_t *)vcomlut, 220);
if (vcomlut) free(vcomlut);
@@ -309,16 +319,19 @@ void uc8159::loadLUTSfromEEPROM(uint8_t bracket, bool doRed) {
xonlut->part[0].repeat = 1;
xonLutSkip(xonlut, 2);
if (!doRed) {
xonLutSkip(xonlut, 3);
xonLutSkip(xonlut, 3);
xonLutSkip(xonlut, 3);
xonLutSkip(xonlut, 2);
xonLutSkip(xonlut, 2);
xonLutSkip(xonlut, 2);
xonLutSkip(xonlut, 2);
}
epdBlockWrite(EPD_LUT_XON, (uint8_t *)xonlut, 200);
if (xonlut) free(xonlut);
}
void uc8159::epdReset() {
uint8_t v0 = 5;
#ifdef DEBUG_EPD
printf("EPD: Reset... ");
#endif
while (1) {
GPIO_WritePinOutput(EPD_RESET, GPIO_IO_HIGH);
delay(100);
@@ -335,7 +348,9 @@ void uc8159::epdReset() {
}
}
delay(5000);
#ifdef DEBUG_EPD
printf("complete.\n");
#endif
}
void uc8159::eepromReadBlock(char a1, uint16_t readaddress, uint8_t *target, uint16_t length) {
@@ -406,6 +421,7 @@ void uc8159::epdWriteDisplayData() {
enableHardSPI(true);
GPIO_WritePinOutput(EPD_CS, GPIO_IO_LOW);
for (uint16_t curY = 0; curY < this->effectiveYRes; curY += blocksize) { //
wdt10s();
memset(screenrow_bw, 0, byteWidth * blocksize);
memset(screenrow_r, 0, byteWidth * blocksize);
@@ -413,7 +429,11 @@ void uc8159::epdWriteDisplayData() {
drawItem::renderDrawLine(screenrow_bw + (byteWidth * bcount), curY + bcount, 0);
}
for (uint8_t bcount = 0; bcount < blocksize; bcount++) {
drawItem::renderDrawLine(screenrow_r + (byteWidth * bcount), curY + bcount, 1);
if (this->bpp == 1) {
drawItem::renderDrawLine(screenrow_bw + (byteWidth * bcount), curY + bcount, 1);
} else {
drawItem::renderDrawLine(screenrow_r + (byteWidth * bcount), curY + bcount, 1);
}
}
for (uint8_t bcount = 0; bcount < blocksize; bcount++) {
@@ -435,9 +455,9 @@ void uc8159::draw() {
}
void uc8159::drawNoWait() {
wdt60s();
epdWriteDisplayData();
if (drawLut) {
// epdWrite(EPD_PLL_CONTROL, 1, 0x3A); // scan the gates a little faster
epdWrite(EPD_PANEL_SETTING, 2, 0xC3, 0x88); // 0xC3-0x88 // lut from register
bool doReds = true;
if (drawLut == 2) doReds = false;
@@ -448,15 +468,21 @@ void uc8159::drawNoWait() {
busyWaitUntil(EPD_IS_BUSY, 10);
busyWaitUntil(!EPD_IS_BUSY, 100);
}
#ifdef DEBUG_EPD
printf("EPD: Draw start\n");
#endif
wdt10s();
epdWrite(EPD_REFRESH, 0);
busyWaitUntil(EPD_IS_BUSY, 10);
}
void uc8159::epdWaitRdy() {
// do_sleeped_epd_refresh();
busyWaitUntil(!EPD_IS_BUSY, 300000);
delay(15000);
do_sleeped_epd_refresh();
// busyWaitUntil(!EPD_IS_BUSY, 300000);
#ifdef DEBUG_EPD
printf("EPD: Draw done!\n");
#endif
}
void uc8159::epdEnterSleep() {

View File

@@ -12,7 +12,7 @@
#include "proto.h"
#include "screen.h"
#include "settings.h"
#include "syncedproto.h" // for APmac / Channel
#include "oepl-protocol.h" // for APmac / Channel
#include "mz100/timer.h"
#include "drawing.h"
@@ -28,12 +28,17 @@ bool __attribute__((section(".aonshadow"))) noAPShown = false;
void addOverlay() {
if ((currentChannel == 0) && (tagSettings.enableNoRFSymbol)) {
// drawImg(0, 3, norf);
drawMask((epd->Xres - 48) - 5, 8, 48, 42, COLOR_BLACK);
drawMask((epd->Xres - 48) - 5, 8, 48, 42, COLOR_RED);
addCompressedFSImage((epd->Xres - 48) - 5, 8, rotation::ROTATE_0, (char *)"norf.bin.z");
noAPShown = true;
} else {
noAPShown = false;
}
if ((batteryVoltage < tagSettings.batLowVoltage) && (tagSettings.enableLowBatSymbol)) {
// drawImg(0, 366, batlow);
drawMask((epd->Xres - 48) - 5, (epd->Yres - 26) - 7, 48, 26, COLOR_BLACK);
drawMask((epd->Xres - 48) - 5, (epd->Yres - 26) - 7, 48, 26, COLOR_RED);
addCompressedFSImage((epd->Xres - 48) - 5, (epd->Yres - 26) - 7, rotation::ROTATE_0, (char *)"lowbat.bin.z");
lowBatteryShown = true;
} else {
lowBatteryShown = false;
@@ -63,16 +68,14 @@ void afterFlashScreenSaver() {
void showSplashScreen() {
fs->init();
epdSetup();
// addCompressedFSImage(300, 80,rotation::ROTATE_0, (char *)"img_tbird.bin.z");
// addCompressedFSImage(228, 24, rotation::ROTATE_0, (char *)"img/sadpanda.z");
// addCompressedFSImage(0, 0, rotation::ROTATE_0, (char *)"forecast75.raw.z");
addCompressedFSImage((640 - 365) - 20, (384 - 237) / 2, rotation::ROTATE_0, (char *)"tbird2.bin.z");
fontrender fr((char *)"font/FreeSansBold24pt7b");
fr.epdPrintf(5, 5, 0, rotation::ROTATE_0, (char *)"OpenEPaperLink");
fr.setFont((char *)"font/FreeSansBold18pt7b");
fr.epdPrintf(20, 70, 1, rotation::ROTATE_0, "M2 7.5\"");
fr.epdPrintf(10, 350, 0, rotation::ROTATE_0, "Tag MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addQR(80, 160, 3, 3, "https://openepaperlink.eu/tag/0/%02X/%02X%02X%02X%02X%02X%02X%02X%02X/", tag.OEPLtype, mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
selectLUT(1);
draw();
epdEnterSleep();
@@ -80,12 +83,14 @@ void showSplashScreen() {
void showApplyUpdate() {
epdSetup();
fontrender fr((char *)"font/FreeSansBold24pt7b");
fr.epdPrintf(5, 5, 0, rotation::ROTATE_0, (char *)"Updating...");
fr.setFont((char *)"font/FreeSansBold18pt7b");
fr.epdPrintf(40, 160, 1, rotation::ROTATE_0, "This shouldn't take too long!");
// epdPrintf(90, 170, 1, "Performing update... This shouldn't take too long!");
fs->init();
fontrender fr((char *)"font/FreeSansBold24pt7b");
fr.epdPrintf(5, 5, 0, rotation::ROTATE_0, (char *)"Updating......");
fr.setFont((char *)"font/FreeSansBold18pt7b");
fr.epdPrintf(40, 140, 1, rotation::ROTATE_0, "This shouldn't take too long!");
// epdPrintf(90, 170, 1, "Performing update... This shouldn't take too long!");
addCompressedFSImage((640 - 551) / 2, 384 - 198, rotation::ROTATE_0, (char *)"jet.bin.z");
addOverlay();
drawNoWait();
}
@@ -93,6 +98,9 @@ void showApplyUpdate() {
void showAPFound() {
fs->init();
epdSetup();
// addCompressedFSImage(228, 24, rotation::ROTATE_0, (char *)"img/sadpanda.z");
fontrender fr((char *)"font/FreeSansBold24pt7b");
fr.epdPrintf(5, 5, 0, rotation::ROTATE_0, (char *)"OpenEPaperLink");
fr.setFont((char *)"font/FreeSansBold18pt7b");
@@ -100,25 +108,32 @@ void showAPFound() {
fr.epdPrintf(20, 110, 0, rotation::ROTATE_0, "AP MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", APmac[7], APmac[6], APmac[5], APmac[4], APmac[3], APmac[2], APmac[1], APmac[0]);
fr.epdPrintf(10, 315, 0, rotation::ROTATE_0, "Battery: %d.%dV", batteryVoltage / 1000, batteryVoltage % 1000);
fr.epdPrintf(10, 350, 0, rotation::ROTATE_0, "Tag MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
selectLUT(1);
addOverlay();
if (lowBatteryShown) {
selectLUT(0);
} else {
selectLUT(1);
}
draw();
epdEnterSleep();
}
void showNoAP() {
fs->init();
epdSetup();
addCompressedFSImage(228, 24, rotation::ROTATE_0, (char *)"img/sadpanda.z");
// addCompressedFSImage(0, 0, rotation::ROTATE_0, (char *)"forecast75.raw.z");
selectLUT(0);
addCompressedFSImage(640 - 415, 384 - 198, rotation::ROTATE_0, (char *)"sadpanda.bin.z");
fontrender fr((char *)"font/FreeSansBold24pt7b");
fr.epdPrintf(5, 5, 0, rotation::ROTATE_0, (char *)"No AP Found!");
fr.setFont((char *)"font/FreeSansBold18pt7b");
fr.epdPrintf(20, 70, 1, rotation::ROTATE_0, "We'll try again later\"");
fr.epdPrintf(20, 70, 0, rotation::ROTATE_0, "We'll try again later");
// epdPrintf(10, 10, 1, "OpenEPaperLink ");
// epdPrintf(10, 40, 1, "No AP found... We'll try again in a little while though!");
// epdPrintf(10, 350, 1, "Tag MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
drawMask(10, 360, 300, 16, COLOR_BLACK);
drawMask(10, 360, 300, 16, COLOR_RED);
fr.setFont((char *)"font/FreeSans9pt7b");
fr.epdPrintf(10, 360, 0, rotation::ROTATE_0, "Tag MAC: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X", mSelfMac[7], mSelfMac[6], mSelfMac[5], mSelfMac[4], mSelfMac[3], mSelfMac[2], mSelfMac[1], mSelfMac[0]);
addOverlay();
draw();
epdEnterSleep();