mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 04:06:29 +01:00
beta v0027 M2-7.5" FW
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
|
||||
#include "epd_interface.h"
|
||||
|
||||
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -30,4 +30,4 @@
|
||||
|
||||
|
||||
#define RADIO_FIRST_CHANNEL (11) //2.4-GHz channels start at 11
|
||||
void applyUpdate();
|
||||
void applyUpdate(uint32_t len);
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 :)
|
||||
|
||||
|
||||
90
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/oepl-protocol.cpp
Normal file
90
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/oepl-protocol.cpp
Normal 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"
|
||||
10
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/oepl-protocol.h
Normal file
10
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/oepl-protocol.h
Normal 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"
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@ class OEPLFs {
|
||||
OEPLFs();
|
||||
std::vector<OEPLFSFile*> files;
|
||||
OEPLFile* getFile(char* name);
|
||||
void deleteFile(char* name);
|
||||
void init();
|
||||
bool isStarted = false;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
159
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/powermgt.cpp
Normal file
159
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/powermgt.cpp
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
107
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/settings.cpp
Normal file
107
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/settings.cpp
Normal 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;
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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);
|
||||
11
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/tagprofile_struct.h
Normal file
11
ARM_Tag_FW/88MZ100_OpenEpaperLink_7.4/tagprofile_struct.h
Normal 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));
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user