mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 21:06:08 +01:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
617b49eb86 | ||
|
|
5868abf189 | ||
|
|
94be1ea3aa | ||
|
|
5190327d5a | ||
|
|
6ecf6410ee | ||
|
|
e72e89d85e | ||
|
|
054146677f | ||
|
|
58d9fe2217 | ||
|
|
5196c1b212 |
10
.github/workflows/release.yml
vendored
10
.github/workflows/release.yml
vendored
@@ -71,7 +71,7 @@ jobs:
|
||||
- name: Combine binaries for Simple_AP
|
||||
run: |
|
||||
cd /home/runner/work/OpenEPaperLink/OpenEPaperLink/Simple_AP
|
||||
esptool.py --chip esp32 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 40m --flash_size 4MB 0x1000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin
|
||||
esptool.py --chip esp32 merge_bin -o merged-firmware.bin --flash_mode dio --flash_freq 40m --flash_size 4MB 0x1000 bootloader.bin 0x8000 partitions.bin 0xe000 boot_app0.bin 0x10000 firmware.bin 0x290000 littlefs.bin
|
||||
|
||||
- name: Build firmware for OpenEPaperLink_Mini_AP
|
||||
run: |
|
||||
@@ -153,17 +153,17 @@ jobs:
|
||||
|
||||
- name: generate release json file
|
||||
run: |
|
||||
mkdir jsonfiles
|
||||
python genfilelist.py ${{ github.ref_name }} $GITHUB_REPOSITORY $GITHUB_SHA
|
||||
|
||||
- name: Add file list to release
|
||||
- name: Add file lists to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
with:
|
||||
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
file: /home/runner/work/OpenEPaperLink/OpenEPaperLink/files.json
|
||||
asset_name: files.json
|
||||
file: jsonfiles/*
|
||||
tag: ${{ github.ref }}
|
||||
file_glob: true
|
||||
overwrite: true
|
||||
body: "file list"
|
||||
|
||||
- name: Add esp bins to release
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
|
||||
@@ -406,5 +406,132 @@
|
||||
"type": "text"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"name": "Send Command",
|
||||
"desc": "Send a command to a tag to execute",
|
||||
"hwtype": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
17,
|
||||
240
|
||||
],
|
||||
"param": [
|
||||
{
|
||||
"key": "cmd",
|
||||
"name": "CMD",
|
||||
"desc": "Action",
|
||||
"type": "select",
|
||||
"options": {
|
||||
"0": "Reboot",
|
||||
"1": "Scan Channels",
|
||||
"2": "Clear settings"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"name": "Set Tag Config",
|
||||
"desc": "Sets tag options. The options you see below are the default options. This may or may not match current tag settings",
|
||||
"hwtype": [
|
||||
0,
|
||||
1,
|
||||
2,
|
||||
17,
|
||||
240
|
||||
],
|
||||
"param": [
|
||||
{
|
||||
"key": "fastboot",
|
||||
"name": "Boot method",
|
||||
"desc": "How the tag should boot, fast or normal",
|
||||
"type": "select",
|
||||
"options": {
|
||||
"0": "-Normal boot",
|
||||
"1": "Fast boot"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "rfwake",
|
||||
"name": "RF Wake",
|
||||
"desc": "If the tag should support RF wake or not. This adds a 0.9µA current draw",
|
||||
"type": "select",
|
||||
"options": {
|
||||
"0": "-Disabled",
|
||||
"1": "Enabled"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "tagroaming",
|
||||
"name": "Tag Roaming",
|
||||
"desc": "If enabled, the tag will periodically scan for AP's and will switch to a different channel if a stronger signal is found",
|
||||
"type": "select",
|
||||
"options": {
|
||||
"0": "-Disabled",
|
||||
"1": "Enabled"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "tagscanontimeout",
|
||||
"name": "Scan for AP on timeout",
|
||||
"desc": "If a tag hasn't found an AP for an hour, should it rescan the channels for another AP?",
|
||||
"type": "select",
|
||||
"options": {
|
||||
"1": "-Enabled",
|
||||
"0": "Disabled"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "showlowbat",
|
||||
"name": "Low Battery symbol",
|
||||
"desc": "Should the tag display the 'low battery' symbol if the battery a voltage threshold has been reached?",
|
||||
"type": "select",
|
||||
"options": {
|
||||
"1": "-Enabled",
|
||||
"0": "Disabled"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "shownorf",
|
||||
"name": "No AP symbol",
|
||||
"desc": "Should the tag display the 'No-signal/AP' symbol if it hasn't been able to contact an AP?",
|
||||
"type": "select",
|
||||
"options": {
|
||||
"1": "-Enabled",
|
||||
"0": "Disabled"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "lowvoltage",
|
||||
"name": "Low voltage threshold",
|
||||
"desc": "Below what voltage should the tag display the 'low bat' symbol?",
|
||||
"type": "select",
|
||||
"options": {
|
||||
"2600": "-2.6v",
|
||||
"2500": "2.5v",
|
||||
"2400": "2.4v",
|
||||
"2300": "2.3v",
|
||||
"2200": "2.2v"
|
||||
}
|
||||
},
|
||||
{
|
||||
"key": "fixedchannel",
|
||||
"name": "Fixed Channel",
|
||||
"desc": "What channel should the tag initially join?",
|
||||
"type": "select",
|
||||
"options": {
|
||||
"0": "-Auto",
|
||||
"11": "11",
|
||||
"15": "15",
|
||||
"20": "20",
|
||||
"25": "25",
|
||||
"26": "26",
|
||||
"27": "27"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -24,13 +24,13 @@ const apstate = [
|
||||
{ state: "requires power cycle", color: "purple" },
|
||||
{ state: "failed", color: "red" },
|
||||
{ state: "coming online", color: "yellow" }
|
||||
];
|
||||
];
|
||||
const runstate = [
|
||||
{ state: "⏹︎ stopped" },
|
||||
{ state: "⏸pause" },
|
||||
{ state: "" }, // hide running
|
||||
{ state: "⏳︎ init" }
|
||||
];
|
||||
];
|
||||
|
||||
const imageQueue = [];
|
||||
let isProcessing = false;
|
||||
@@ -48,7 +48,7 @@ window.addEventListener("load", function () {
|
||||
this.document.title = data.alias;
|
||||
}
|
||||
});
|
||||
fetch('/content_cards.json')
|
||||
fetch('/content_cards.json')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
cardconfig = data;
|
||||
@@ -307,7 +307,7 @@ $('#taglist').addEventListener("click", (event) => {
|
||||
$('#cfgalias').value = tagdata.alias;
|
||||
$('#cfgmore').style.display = "none";
|
||||
if (populateSelectTag(tagdata.hwType, tagdata.capabilities)) {
|
||||
$('#cfgcontent').parentNode.style.display = "flex";
|
||||
$('#cfgcontent').parentNode.style.display = "flex";
|
||||
$('#cfgcontent').value = tagdata.contentMode;
|
||||
$('#cfgcontent').dataset.json = tagdata.modecfgjson;
|
||||
contentselected();
|
||||
@@ -354,7 +354,7 @@ $('#cfgsave').onclick = function () {
|
||||
|
||||
formData.append("rotate", $('#cfgrotate').value);
|
||||
formData.append("lut", $('#cfglut').value);
|
||||
|
||||
|
||||
fetch("/save_cfg", {
|
||||
method: "POST",
|
||||
body: formData
|
||||
@@ -530,6 +530,12 @@ function contentselected() {
|
||||
const optionElement = document.createElement("option");
|
||||
optionElement.value = key;
|
||||
optionElement.text = element.options[key];
|
||||
if (element.options[key].substring(0,1)=="-") {
|
||||
optionElement.text = element.options[key].substring(1);
|
||||
optionElement.selected = true;
|
||||
} else {
|
||||
optionElement.selected = false;
|
||||
}
|
||||
input.appendChild(optionElement);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -107,4 +107,19 @@ struct TagInfo {
|
||||
uint8_t contentMode;
|
||||
} __packed;
|
||||
|
||||
struct tagsettings {
|
||||
uint8_t settingsVer; // the version of the struct as written to the infopage
|
||||
uint8_t enableFastBoot; // default 0; if set, it will skip splashscreen
|
||||
uint8_t enableRFWake; // default 0; if set, it will enable RF wake. This will add about ~0.9µA idle power consumption
|
||||
uint8_t enableTagRoaming; // default 0; if set, the tag will scan for an accesspoint every few check-ins. This will increase power consumption quite a bit
|
||||
uint8_t enableScanForAPAfterTimeout; // default 1; if a the tag failed to check in, after a few attempts it will try to find a an AP on other channels
|
||||
uint8_t enableLowBatSymbol; // default 1; tag will show 'low battery' icon on screen if the battery is depleted
|
||||
uint8_t enableNoRFSymbol; // default 1; tag will show 'no signal' icon on screen if it failed to check in for a longer period of time
|
||||
uint8_t fastBootCapabilities; // holds the byte with 'capabilities' as detected during a normal tag boot; allows the tag to skip detecting buttons and NFC chip
|
||||
uint8_t customMode; // default 0; if anything else, tag will bootup in a different 'mode'
|
||||
uint16_t batLowVoltage; // Low battery threshold voltage (2450 for 2.45v). defaults to BATTERY_VOLTAGE_MINIMUM from powermgt.h
|
||||
uint16_t minimumCheckInTime; // defaults to BASE_INTERVAL from powermgt.h
|
||||
uint8_t fixedChannel; // default 0; if set to a valid channel number, the tag will stick to that channel
|
||||
} __packed;
|
||||
|
||||
#pragma pack(pop)
|
||||
@@ -37,5 +37,6 @@ String windDirectionIcon(int degrees);
|
||||
void getLocation(JsonObject &cfgobj);
|
||||
void prepareNFCReq(uint8_t* dst, const char* url);
|
||||
void prepareLUTreq(uint8_t *dst, String input);
|
||||
void prepareConfigFile(uint8_t *dst, JsonObject config);
|
||||
void getTemplate(JsonDocument &json, const char *filePath, uint8_t id, uint8_t hwtype);
|
||||
void setU8G2Font(const String &title, U8g2_for_TFT_eSPI &u8f);
|
||||
|
||||
@@ -12,6 +12,7 @@ extern void processXferComplete(struct espXferComplete* xfc, bool local);
|
||||
extern void processXferTimeout(struct espXferComplete* xfc, bool local);
|
||||
extern void processDataReq(struct espAvailDataReq* adr, bool local);
|
||||
|
||||
extern bool sendTagCommand(uint8_t* dst, uint8_t cmd, bool local);
|
||||
extern bool sendAPSegmentedData(uint8_t* dst, String data, uint16_t icons, bool inverted, bool local);
|
||||
extern bool showAPSegmentedInfo(uint8_t* dst, bool local);
|
||||
extern void updateTaginfoitem(struct TagInfo* taginfoitem);
|
||||
|
||||
@@ -100,8 +100,8 @@ build_flags =
|
||||
-D FLASHER_AP_RESET=37
|
||||
-D FLASHER_AP_POWER={16,17,18,21}
|
||||
-D FLASHER_AP_TXD=35
|
||||
-D FLASHER_AP_RXD=36
|
||||
-D FLASHER_AP_TEST=34
|
||||
-D FLASHER_AP_RXD=34
|
||||
-D FLASHER_AP_TEST=36
|
||||
-D FLASHER_LED=15
|
||||
-D FLASHER_RGB_LED=-1
|
||||
|
||||
|
||||
@@ -286,6 +286,19 @@ void drawNew(uint8_t mac[8], bool buttonPressed, tagRecord *&taginfo) {
|
||||
taginfo->nextupdate = now + (cfgobj["ttl"].as<int>() < 5 ? 5 : cfgobj["ttl"].as<int>()) * 60;
|
||||
updateTagImage(filename, mac, (cfgobj["ttl"].as<int>() < 5 ? 5 : cfgobj["ttl"].as<int>()), taginfo, imageParams);
|
||||
break;
|
||||
|
||||
case 17: // tag command
|
||||
sendTagCommand(mac, cfgobj["cmd"].as<int>(), (taginfo->isExternal == false));
|
||||
cfgobj["filename"] = "";
|
||||
taginfo->nextupdate = 3216153600;
|
||||
taginfo->contentMode = Image;
|
||||
break;
|
||||
case 18:
|
||||
prepareConfigFile(mac, cfgobj);
|
||||
cfgobj["filename"] = "";
|
||||
taginfo->nextupdate = 3216153600;
|
||||
taginfo->contentMode = Image;
|
||||
break;
|
||||
}
|
||||
|
||||
taginfo->modeConfigJson = doc.as<String>();
|
||||
@@ -1000,6 +1013,23 @@ void prepareLUTreq(uint8_t *dst, String input) {
|
||||
prepareDataAvail(waveform, waveformLen, DATATYPE_CUSTOM_LUT_OTA, dst);
|
||||
}
|
||||
|
||||
void prepareConfigFile(uint8_t *dst, JsonObject config) {
|
||||
struct tagsettings tagSettings;
|
||||
tagSettings.settingsVer = 1;
|
||||
tagSettings.enableFastBoot = config["fastboot"].as<int>();
|
||||
tagSettings.enableRFWake = config["rfwake"].as<int>();
|
||||
tagSettings.enableTagRoaming = config["tagroaming"].as<int>();
|
||||
tagSettings.enableScanForAPAfterTimeout = config["tagscanontimeout"].as<int>();
|
||||
tagSettings.enableLowBatSymbol = config["showlowbat"].as<int>();
|
||||
tagSettings.enableNoRFSymbol = config["shownorf"].as<int>();
|
||||
tagSettings.customMode = 0;
|
||||
tagSettings.fastBootCapabilities = 0;
|
||||
tagSettings.minimumCheckInTime = 1;
|
||||
tagSettings.fixedChannel = config["fixedchannel"].as<int>();
|
||||
tagSettings.batLowVoltage = config["lowvoltage"].as<int>();
|
||||
prepareDataAvail((uint8_t *)&tagSettings, sizeof(tagSettings), 0xA8, dst);
|
||||
}
|
||||
|
||||
void getTemplate(JsonDocument &json, const char *filePath, uint8_t id, uint8_t hwtype) {
|
||||
File jsonFile = LittleFS.open(filePath, "r");
|
||||
if (!jsonFile) {
|
||||
|
||||
@@ -587,6 +587,26 @@ bool showAPSegmentedInfo(uint8_t* dst, bool local) {
|
||||
}
|
||||
}
|
||||
|
||||
bool sendTagCommand(uint8_t* dst, uint8_t cmd, bool local) {
|
||||
struct pendingData pending = {0};
|
||||
memcpy(pending.targetMac, dst, 8);
|
||||
pending.availdatainfo.dataType = 0xAF;
|
||||
pending.availdatainfo.dataTypeArgument = cmd;
|
||||
pending.availdatainfo.nextCheckIn = 0;
|
||||
pending.attemptsLeft = 120;
|
||||
char buffer[64];
|
||||
sprintf(buffer, ">Tag CMD %02X%02X%02X%02X%02X%02X%02X%02X\n\0", dst[7], dst[6], dst[5], dst[4], dst[3], dst[2], dst[1], dst[0]);
|
||||
Serial.print(buffer);
|
||||
if (local) {
|
||||
return sendDataAvail(&pending);
|
||||
} else {
|
||||
udpsync.netSendDataAvail(&pending);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void updateTaginfoitem(struct TagInfo* taginfoitem) {
|
||||
tagRecord* taginfo = nullptr;
|
||||
taginfo = tagRecord::findByMAC(taginfoitem->mac);
|
||||
|
||||
@@ -606,7 +606,7 @@ bool bringAPOnline() {
|
||||
}
|
||||
|
||||
void APTask(void* parameter) {
|
||||
xTaskCreate(rxCmdProcessor, "rxCmdProcessor", 3000, NULL, configMAX_PRIORITIES - 10, NULL);
|
||||
xTaskCreate(rxCmdProcessor, "rxCmdProcessor", 4000, NULL, configMAX_PRIORITIES - 10, NULL);
|
||||
xTaskCreate(rxSerialTask, "rxSerialTask", 1750, NULL, configMAX_PRIORITIES - 4, NULL);
|
||||
|
||||
#if (AP_PROCESS_PORT == FLASHER_AP_PORT)
|
||||
|
||||
BIN
binaries/AP_force_flash.bin
Executable file
BIN
binaries/AP_force_flash.bin
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -67,6 +67,14 @@ jsonarray = {
|
||||
"tagota": tagota,
|
||||
}
|
||||
|
||||
json_file_path = "files.json"
|
||||
with open(json_file_path, "w") as json_file:
|
||||
with open("jsonfiles/binaries.json", "w") as json_file:
|
||||
json.dump(binaries, json_file, indent=4)
|
||||
|
||||
with open("jsonfiles/files.json", "w") as json_file:
|
||||
json.dump(jsonarray, json_file, indent=4)
|
||||
|
||||
with open("jsonfiles/tagota.json", "w") as json_file:
|
||||
json.dump(tagota, json_file, indent=4)
|
||||
|
||||
with open("jsonfiles/filesystem.json", "w") as json_file:
|
||||
json.dump(files1, json_file, indent=4)
|
||||
|
||||
@@ -20,7 +20,14 @@
|
||||
#define DATATYPE_IMG_RAW_1BPP 0x20 // 2888 bytes for 1.54" / 4736 2.9" / 15000 4.2"
|
||||
#define DATATYPE_IMG_RAW_2BPP 0x21 // 5776 bytes for 1.54" / 9472 2.9" / 30000 4.2"
|
||||
#define DATATYPE_IMG_RAW_1BPP_DIRECT 0x3F // only for 1.54", don't write to EEPROM, but straightaway to the EPD
|
||||
#define DATATYPE_UK_SEGMENTED 0x51 // Segmented data for the UK Segmented display type
|
||||
#define DATATYPE_UK_SEGMENTED 0x51 // Segmented data for the UK Segmented display type (contained in availableData Reply)
|
||||
#define DATATYPE_EU_SEGMENTED 0x52 // Segmented data for the EU/DE Segmented display type (contained in availableData Reply)
|
||||
#define DATATYPE_NFC_RAW_CONTENT 0xA0 // raw memory content for the NT3H1101
|
||||
#define DATATYPE_NFC_URL_DIRECT 0xA1 // URL format for NT3H1101
|
||||
#define DATATYPE_TAG_CONFIG_DATA 0xA8 // Config data for tag
|
||||
#define DATATYPE_COMMAND_DATA 0xAF // Command for the tag to execute (contained in availableData Reply)
|
||||
#define DATATYPE_CUSTOM_LUT_OTA 0xB0 // Custom OTA updated LUT
|
||||
|
||||
#define CMD_DO_REBOOT 0
|
||||
#define CMD_DO_SCAN 1
|
||||
#define CMD_DO_RESET_SETTINGS 2
|
||||
@@ -5,7 +5,7 @@ BUILD ?= zbs29_ssd1619
|
||||
SOURCES += main.c eeprom.c drawing.c
|
||||
SOURCES += comms.c
|
||||
SOURCES += syncedproto.c userinterface.c
|
||||
SOURCES += powermgt.c barcode.c i2cdevices.c
|
||||
SOURCES += powermgt.c barcode.c i2cdevices.c settings.c
|
||||
|
||||
all: #make sure it is the first target
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ bool supportsNFCWake() {
|
||||
}
|
||||
if (pcount < 10000) {
|
||||
// P1_3 (Field Detect) dropped to 'low' pretty fast, this means the load on this pin is high
|
||||
pr("This tag currently does not support NFC wake, load on the FD pin (P1.3) is pretty high.\nOn some boards, a pull-up resistor backpowers the NFC IC. Consider removing it!\n");
|
||||
pr("NFC: This tag currently does not support NFC wake, load on the FD pin (P1.3) is pretty high.\nOn some boards, a pull-up resistor backpowers the NFC IC. Consider removing it!\n");
|
||||
return false;
|
||||
} else {
|
||||
// No reason to believe this pin is currently loaded down severely
|
||||
@@ -121,7 +121,7 @@ bool i2cCheckDevice(uint8_t address) {
|
||||
iictest.deviceAddr = address << 1;
|
||||
uint8_t res = i2cTransact(&iictest, 1);
|
||||
if (res == 0) {
|
||||
pr("Found i2c device at 0x%02X\n", address);
|
||||
pr("I2C: Device found at 0x%02X\n", address);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -23,6 +23,12 @@
|
||||
|
||||
// #define DEBUG_MODE
|
||||
|
||||
static const uint64_t __code __at(0x008b) mVersionRom = 0x1000011300000000ull;
|
||||
|
||||
#define TAG_MODE_CHANSEARCH 0
|
||||
#define TAG_MODE_ASSOCIATED 1
|
||||
uint8_t currentTagMode = TAG_MODE_CHANSEARCH;
|
||||
|
||||
void displayLoop() {
|
||||
powerUp(INIT_BASE | INIT_UART);
|
||||
|
||||
@@ -118,6 +124,7 @@ uint8_t showChannelSelect() { // returns 0 if no accesspoints were found
|
||||
return highestSlot;
|
||||
}
|
||||
uint8_t channelSelect() { // returns 0 if no accesspoints were found
|
||||
powerUp(INIT_RADIO);
|
||||
uint8_t __xdata result[16];
|
||||
memset(result, 0, sizeof(result));
|
||||
|
||||
@@ -128,7 +135,7 @@ uint8_t channelSelect() { // returns 0 if no accesspoints were found
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
powerDown(INIT_RADIO);
|
||||
uint8_t __xdata highestLqi = 0;
|
||||
uint8_t __xdata highestSlot = 0;
|
||||
for (uint8_t c = 0; c < sizeof(result); c++) {
|
||||
@@ -142,79 +149,54 @@ uint8_t channelSelect() { // returns 0 if no accesspoints were found
|
||||
return highestSlot;
|
||||
}
|
||||
|
||||
void main() {
|
||||
// displayLoop(); // remove me
|
||||
setupPortsInitial();
|
||||
powerUp(INIT_BASE | INIT_UART);
|
||||
|
||||
void validateMacAddress() {
|
||||
// check if the mac contains at least some non-0xFF values
|
||||
for (uint8_t __xdata c = 0; c < 8; c++) {
|
||||
if (mSelfMac[c] != 0xFF) goto macIsValid;
|
||||
}
|
||||
// invalid mac address. Display warning screen and sleep forever
|
||||
pr("Mac can't be all FF's.\n");
|
||||
powerUp(INIT_EPD);
|
||||
showNoMAC();
|
||||
powerDown(INIT_EPD | INIT_UART | INIT_EEPROM);
|
||||
doSleep(-1);
|
||||
wdtDeviceReset();
|
||||
macIsValid:
|
||||
return;
|
||||
}
|
||||
uint8_t getFirstWakeUpReason() {
|
||||
if (RESET & 0x01) {
|
||||
wakeUpReason = WAKEUP_REASON_WDT_RESET;
|
||||
pr("WDT reset!\n");
|
||||
} else {
|
||||
wakeUpReason = WAKEUP_REASON_FIRSTBOOT;
|
||||
return WAKEUP_REASON_WDT_RESET;
|
||||
}
|
||||
|
||||
wdt10s();
|
||||
|
||||
boardGetOwnMac(mSelfMac);
|
||||
|
||||
{
|
||||
bool __xdata macSet = false;
|
||||
for (uint8_t __xdata c = 0; c < 8; c++) {
|
||||
if (mSelfMac[c] != 0xFF) {
|
||||
macSet = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!macSet) {
|
||||
pr("Mac can't be all FF's.\n");
|
||||
powerUp(INIT_EPD);
|
||||
showNoMAC();
|
||||
powerDown(INIT_EPD | INIT_UART | INIT_EEPROM);
|
||||
doSleep(-1);
|
||||
wdtDeviceReset();
|
||||
}
|
||||
}
|
||||
|
||||
pr("BOOTED> %d.%d.%d%s\n", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
|
||||
|
||||
return WAKEUP_REASON_FIRSTBOOT;
|
||||
}
|
||||
void checkI2C() {
|
||||
powerUp(INIT_I2C);
|
||||
|
||||
//i2cBusScan();
|
||||
|
||||
// i2cBusScan();
|
||||
if (i2cCheckDevice(0x55)) {
|
||||
powerDown(INIT_I2C);
|
||||
// found something!
|
||||
capabilities |= CAPABILITY_HAS_NFC;
|
||||
if (supportsNFCWake()) {
|
||||
pr("This board supports NFC wake!\n");
|
||||
pr("NFC: NFC Wake Supported\n");
|
||||
capabilities |= CAPABILITY_NFC_WAKE;
|
||||
}
|
||||
} else {
|
||||
pr("I2C: No devices found");
|
||||
// didn't find a NFC chip on the expected ID
|
||||
powerDown(INIT_I2C);
|
||||
}
|
||||
}
|
||||
|
||||
pr("MAC>%02X%02X", mSelfMac[0], mSelfMac[1]);
|
||||
pr("%02X%02X", mSelfMac[2], mSelfMac[3]);
|
||||
pr("%02X%02X", mSelfMac[4], mSelfMac[5]);
|
||||
pr("%02X%02X\n", mSelfMac[6], mSelfMac[7]);
|
||||
|
||||
powerUp(INIT_RADIO); // load down the battery using the radio to get a good voltage reading
|
||||
powerUp(INIT_EPD_VOLTREADING | INIT_TEMPREADING);
|
||||
powerDown(INIT_RADIO);
|
||||
|
||||
powerUp(INIT_EEPROM);
|
||||
// get the highest slot number, number of slots
|
||||
initializeProto();
|
||||
powerDown(INIT_EEPROM);
|
||||
|
||||
void detectButtonOrJig() {
|
||||
switch (checkButtonOrJig()) {
|
||||
case DETECT_P1_0_BUTTON:
|
||||
capabilities |= CAPABILITY_HAS_WAKE_BUTTON;
|
||||
break;
|
||||
case DETECT_P1_0_JIG:
|
||||
wdt120s();
|
||||
// show the screensaver (minimal text to prevent image burn-in)
|
||||
// show the screensaver, full LUT (minimal text to prevent image burn-in)
|
||||
powerUp(INIT_EPD);
|
||||
afterFlashScreenSaver();
|
||||
while (1)
|
||||
@@ -225,161 +207,258 @@ void main() {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// show the splashscreen
|
||||
powerUp(INIT_EPD);
|
||||
showSplashScreen();
|
||||
void TagAssociated() {
|
||||
// associated
|
||||
struct AvailDataInfo *__xdata avail;
|
||||
// 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)
|
||||
if (voltageCheckCounter == VOLTAGE_CHECK_INTERVAL) {
|
||||
doVoltageReading();
|
||||
voltageCheckCounter = 0;
|
||||
} else {
|
||||
powerUp(INIT_TEMPREADING);
|
||||
}
|
||||
voltageCheckCounter++;
|
||||
|
||||
// check if the battery level is below minimum, and force a redraw of the screen
|
||||
|
||||
if ((lowBattery && !lowBatteryShown && tagSettings.enableLowBatSymbol) || (noAPShown && tagSettings.enableNoRFSymbol)) {
|
||||
// Check if we were already displaying an image
|
||||
if (curImgSlot != 0xFF) {
|
||||
powerUp(INIT_EEPROM | INIT_EPD);
|
||||
wdt60s();
|
||||
drawImageFromEeprom(curImgSlot);
|
||||
powerDown(INIT_EEPROM | INIT_EPD);
|
||||
} else {
|
||||
powerUp(INIT_EPD);
|
||||
showAPFound();
|
||||
powerDown(INIT_EPD);
|
||||
}
|
||||
}
|
||||
|
||||
powerUp(INIT_RADIO);
|
||||
avail = getAvailDataInfo();
|
||||
powerDown(INIT_RADIO);
|
||||
|
||||
if (avail != NULL) {
|
||||
// we got some data!
|
||||
longDataReqCounter = 0;
|
||||
// since we've had succesful contact, and communicated the wakeup reason succesfully, we can now reset to the 'normal' status
|
||||
wakeUpReason = WAKEUP_REASON_TIMED;
|
||||
}
|
||||
if (tagSettings.enableTagRoaming) {
|
||||
uint8_t roamChannel = channelSelect();
|
||||
if (roamChannel) currentChannel = roamChannel;
|
||||
}
|
||||
} else {
|
||||
powerUp(INIT_RADIO);
|
||||
avail = getShortAvailDataInfo();
|
||||
powerDown(INIT_RADIO);
|
||||
}
|
||||
|
||||
addAverageValue();
|
||||
|
||||
if (avail == NULL) {
|
||||
// no data :( this means no reply from AP
|
||||
nextCheckInFromAP = 0; // let the power-saving algorithm determine the next sleep period
|
||||
} else {
|
||||
nextCheckInFromAP = avail->nextCheckIn;
|
||||
// got some data from the AP!
|
||||
if (avail->dataType != DATATYPE_NOUPDATE) {
|
||||
// data transfer
|
||||
if (processAvailDataInfo(avail)) {
|
||||
// succesful transfer, next wake time is determined by the NextCheckin;
|
||||
} else {
|
||||
// failed transfer, let the algorithm determine next sleep interval (not the AP)
|
||||
nextCheckInFromAP = 0;
|
||||
}
|
||||
} else {
|
||||
// no data transfer, just sleep.
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t nextCheckin = getNextSleep();
|
||||
longDataReqCounter += nextCheckin;
|
||||
|
||||
if (nextCheckin == INTERVAL_AT_MAX_ATTEMPTS) {
|
||||
// We've averaged up to the maximum interval, this means the tag hasn't been in contact with an AP for some time.
|
||||
if (tagSettings.enableScanForAPAfterTimeout) {
|
||||
currentTagMode = TAG_MODE_CHANSEARCH;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if the AP told us to sleep for a specific period, do so.
|
||||
if (nextCheckInFromAP) {
|
||||
doSleep(nextCheckInFromAP * 60000UL);
|
||||
} else {
|
||||
doSleep(getNextSleep() * 1000UL);
|
||||
}
|
||||
}
|
||||
|
||||
void TagChanSearch() {
|
||||
// not associated
|
||||
if (((scanAttempts != 0) && (scanAttempts % VOLTAGEREADING_DURING_SCAN_INTERVAL == 0)) || (scanAttempts > (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS))) {
|
||||
doVoltageReading();
|
||||
}
|
||||
|
||||
// try to find a working channel
|
||||
currentChannel = channelSelect();
|
||||
|
||||
// Check if we should redraw the screen with icons, info screen or screensaver
|
||||
if ((!currentChannel && !noAPShown && tagSettings.enableNoRFSymbol) ||
|
||||
(lowBattery && !lowBatteryShown && tagSettings.enableLowBatSymbol) ||
|
||||
(scanAttempts == (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS - 1))) {
|
||||
powerUp(INIT_EPD);
|
||||
wdt60s();
|
||||
if (curImgSlot != 0xFF) {
|
||||
powerUp(INIT_EEPROM);
|
||||
drawImageFromEeprom(curImgSlot);
|
||||
powerDown(INIT_EEPROM);
|
||||
} else if ((scanAttempts >= (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS - 1))) {
|
||||
showLongTermSleep();
|
||||
} else {
|
||||
showNoAP();
|
||||
}
|
||||
powerDown(INIT_EPD);
|
||||
}
|
||||
|
||||
// did we find a working channel?
|
||||
if (currentChannel) {
|
||||
// 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;
|
||||
return;
|
||||
} else {
|
||||
// still not associated
|
||||
doSleep(getNextScanSleep(true) * 1000UL);
|
||||
}
|
||||
}
|
||||
|
||||
void executeCommand(uint8_t cmd) {
|
||||
switch (cmd) {
|
||||
case CMD_DO_REBOOT:
|
||||
wdtDeviceReset();
|
||||
break;
|
||||
case CMD_DO_RESET_SETTINGS:
|
||||
loadDefaultSettings();
|
||||
writeSettings();
|
||||
break;
|
||||
case CMD_DO_SCAN:
|
||||
currentChannel = channelSelect();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void main() {
|
||||
// displayLoop(); // remove me
|
||||
setupPortsInitial();
|
||||
powerUp(INIT_BASE | INIT_UART);
|
||||
pr("BOOTED> %d.%d.%d%s\n", fwVersion / 100, (fwVersion % 100) / 10, (fwVersion % 10), fwVersionSuffix);
|
||||
|
||||
// Find the reason why we're booting; is this a WDT?
|
||||
wakeUpReason = getFirstWakeUpReason();
|
||||
|
||||
// get our own mac address. this is stored in Infopage at offset 0x10-onwards
|
||||
boardGetOwnMac(mSelfMac);
|
||||
pr("MAC>%02X%02X", mSelfMac[0], mSelfMac[1]);
|
||||
pr("%02X%02X", mSelfMac[2], mSelfMac[3]);
|
||||
pr("%02X%02X", mSelfMac[4], mSelfMac[5]);
|
||||
pr("%02X%02X\n", mSelfMac[6], mSelfMac[7]);
|
||||
|
||||
// load settings from infopage
|
||||
loadSettings();
|
||||
|
||||
// get the highest slot number, number of slots
|
||||
initializeProto();
|
||||
|
||||
if (tagSettings.enableFastBoot) {
|
||||
// Fastboot
|
||||
pr("Doing fast boot\n");
|
||||
capabilities = tagSettings.fastBootCapabilities;
|
||||
if (tagSettings.fixedChannel) {
|
||||
currentChannel = tagSettings.fixedChannel;
|
||||
} else {
|
||||
currentChannel = channelSelect();
|
||||
}
|
||||
} else {
|
||||
// Normal boot/startup
|
||||
|
||||
// validate the mac address; this will display a warning on the screen if the mac address is invalid
|
||||
validateMacAddress();
|
||||
|
||||
#if (NFC_TYPE == 1)
|
||||
// initialize I2C
|
||||
checkI2C();
|
||||
#endif
|
||||
|
||||
// Get a voltage reading on the tag, loading down the battery with the radio
|
||||
doVoltageReading();
|
||||
|
||||
// detect button or jig
|
||||
detectButtonOrJig();
|
||||
|
||||
// show the splashscreen
|
||||
pr("EPD: First powerup\n");
|
||||
powerUp(INIT_EPD);
|
||||
showSplashScreen();
|
||||
|
||||
// we've now displayed something on the screen; for the SSD1619, we are now aware of the lut-size
|
||||
#ifdef EPD_SSD1619
|
||||
capabilities |= CAPABILITY_SUPPORTS_CUSTOM_LUTS;
|
||||
if (dispLutSize != 7) {
|
||||
capabilities |= CAPABILITY_ALT_LUT_SIZE;
|
||||
}
|
||||
capabilities |= CAPABILITY_SUPPORTS_CUSTOM_LUTS;
|
||||
if (dispLutSize != 7) {
|
||||
capabilities |= CAPABILITY_ALT_LUT_SIZE;
|
||||
}
|
||||
#endif
|
||||
tagSettings.fastBootCapabilities = capabilities;
|
||||
|
||||
powerUp(INIT_EPD);
|
||||
wdt30s();
|
||||
currentChannel = showChannelSelect();
|
||||
// now that we've collected all possible capabilities, save it to settings
|
||||
writeSettings();
|
||||
|
||||
// scan for channels
|
||||
powerUp(INIT_EPD);
|
||||
wdt30s();
|
||||
if (tagSettings.fixedChannel) {
|
||||
currentChannel = tagSettings.fixedChannel;
|
||||
} else {
|
||||
currentChannel = showChannelSelect();
|
||||
}
|
||||
}
|
||||
|
||||
// end of the fastboot option split
|
||||
wdt10s();
|
||||
|
||||
powerUp(INIT_EPD);
|
||||
if (currentChannel) {
|
||||
showAPFound();
|
||||
initPowerSaving(INTERVAL_BASE);
|
||||
powerDown(INIT_EPD | INIT_UART);
|
||||
currentTagMode = TAG_MODE_ASSOCIATED;
|
||||
doSleep(5000UL);
|
||||
} else {
|
||||
showNoAP();
|
||||
initPowerSaving(INTERVAL_AT_MAX_ATTEMPTS);
|
||||
powerDown(INIT_EPD | INIT_UART);
|
||||
currentTagMode = TAG_MODE_CHANSEARCH;
|
||||
doSleep(120000UL);
|
||||
}
|
||||
|
||||
// this is the loop we'll stay in forever, basically.
|
||||
while (1) {
|
||||
powerUp(INIT_UART);
|
||||
wdt10s();
|
||||
if (currentChannel) {
|
||||
// associated
|
||||
|
||||
struct AvailDataInfo *__xdata avail;
|
||||
// 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)
|
||||
if (voltageCheckCounter == VOLTAGE_CHECK_INTERVAL) {
|
||||
powerUp(INIT_RADIO); // load down the battery using the radio to get a good reading
|
||||
powerUp(INIT_TEMPREADING | INIT_EPD_VOLTREADING);
|
||||
powerDown(INIT_RADIO);
|
||||
voltageCheckCounter = 0;
|
||||
} else {
|
||||
powerUp(INIT_TEMPREADING);
|
||||
}
|
||||
voltageCheckCounter++;
|
||||
|
||||
// check if the battery level is below minimum, and force a redraw of the screen
|
||||
if ((lowBattery && !lowBatteryShown) || (noAPShown)) {
|
||||
// Check if we were already displaying an image
|
||||
if (curImgSlot != 0xFF) {
|
||||
powerUp(INIT_EEPROM | INIT_EPD);
|
||||
wdt60s();
|
||||
drawImageFromEeprom(curImgSlot);
|
||||
powerDown(INIT_EEPROM | INIT_EPD);
|
||||
} else {
|
||||
powerUp(INIT_EPD);
|
||||
showAPFound();
|
||||
powerDown(INIT_EPD);
|
||||
}
|
||||
}
|
||||
powerUp(INIT_RADIO);
|
||||
avail = getAvailDataInfo();
|
||||
powerDown(INIT_RADIO);
|
||||
|
||||
if (avail != NULL) {
|
||||
// we got some data!
|
||||
longDataReqCounter = 0;
|
||||
// since we've had succesful contact, and communicated the wakeup reason succesfully, we can now reset to the 'normal' status
|
||||
wakeUpReason = WAKEUP_REASON_TIMED;
|
||||
}
|
||||
} else {
|
||||
powerUp(INIT_RADIO);
|
||||
avail = getShortAvailDataInfo();
|
||||
powerDown(INIT_RADIO);
|
||||
}
|
||||
|
||||
addAverageValue();
|
||||
|
||||
if (avail == NULL) {
|
||||
// no data :(
|
||||
nextCheckInFromAP = 0; // let the power-saving algorithm determine the next sleep period
|
||||
} else {
|
||||
nextCheckInFromAP = avail->nextCheckIn;
|
||||
// got some data from the AP!
|
||||
if (avail->dataType != DATATYPE_NOUPDATE) {
|
||||
// data transfer
|
||||
if (processAvailDataInfo(avail)) {
|
||||
// succesful transfer, next wake time is determined by the NextCheckin;
|
||||
} else {
|
||||
// failed transfer, let the algorithm determine next sleep interval (not the AP)
|
||||
nextCheckInFromAP = 0;
|
||||
}
|
||||
} else {
|
||||
// no data transfer, just sleep.
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t nextCheckin = getNextSleep();
|
||||
longDataReqCounter += nextCheckin;
|
||||
if (nextCheckin == INTERVAL_AT_MAX_ATTEMPTS) {
|
||||
// disconnected, obviously...
|
||||
currentChannel = 0;
|
||||
}
|
||||
|
||||
// if the AP told us to sleep for a specific period, do so.
|
||||
if (nextCheckInFromAP) {
|
||||
doSleep(nextCheckInFromAP * 60000UL);
|
||||
} else {
|
||||
doSleep(getNextSleep() * 1000UL);
|
||||
}
|
||||
|
||||
} else {
|
||||
// not associated
|
||||
if (((scanAttempts != 0) && (scanAttempts % VOLTAGEREADING_DURING_SCAN_INTERVAL == 0)) || (scanAttempts > (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS))) {
|
||||
powerUp(INIT_RADIO); // load down the battery using the radio to get a good reading
|
||||
powerUp(INIT_EPD_VOLTREADING);
|
||||
powerDown(INIT_RADIO);
|
||||
}
|
||||
// try to find a working channel
|
||||
powerUp(INIT_RADIO);
|
||||
currentChannel = channelSelect();
|
||||
powerDown(INIT_RADIO);
|
||||
|
||||
if ((!currentChannel && !noAPShown) || (lowBattery && !lowBatteryShown) || (scanAttempts == (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS - 1))) {
|
||||
powerUp(INIT_EPD);
|
||||
wdt60s();
|
||||
if (curImgSlot != 0xFF) {
|
||||
powerUp(INIT_EEPROM);
|
||||
drawImageFromEeprom(curImgSlot);
|
||||
powerDown(INIT_EEPROM);
|
||||
} else if ((scanAttempts >= (INTERVAL_1_ATTEMPTS + INTERVAL_2_ATTEMPTS - 1))) {
|
||||
showLongTermSleep();
|
||||
} else {
|
||||
showNoAP();
|
||||
}
|
||||
powerDown(INIT_EPD);
|
||||
}
|
||||
|
||||
// did we find a working channel?
|
||||
if (currentChannel) {
|
||||
// now associated!
|
||||
scanAttempts = 0;
|
||||
wakeUpReason = WAKEUP_REASON_NETWORK_SCAN;
|
||||
initPowerSaving(INTERVAL_BASE);
|
||||
doSleep(getNextSleep() * 1000UL);
|
||||
|
||||
} else {
|
||||
// still not associated
|
||||
doSleep(getNextScanSleep(true) * 1000UL);
|
||||
}
|
||||
switch (currentTagMode) {
|
||||
case TAG_MODE_ASSOCIATED:
|
||||
TagAssociated();
|
||||
break;
|
||||
case TAG_MODE_CHANSEARCH:
|
||||
TagChanSearch();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
45
zbs243_Tag_FW/main.lk
Normal file
45
zbs243_Tag_FW/main.lk
Normal file
@@ -0,0 +1,45 @@
|
||||
-muwx
|
||||
-i main.ihx
|
||||
-M
|
||||
-X 0x2000
|
||||
-C 0xfc00
|
||||
-b HOME = 0x0000
|
||||
-b XSEG = 0xe000
|
||||
-b PSEG = 0xe000
|
||||
-b ISEG = 0x0000
|
||||
-b BSEG = 0x0000
|
||||
-k /usr/local/bin/../share/sdcc/lib/large
|
||||
-k /usr/local/share/sdcc/lib/large
|
||||
-l mcs51
|
||||
-l libsdcc
|
||||
-l libint
|
||||
-l liblong
|
||||
-l libfloat
|
||||
main.rel
|
||||
eeprom.rel
|
||||
drawing.rel
|
||||
comms.rel
|
||||
syncedproto.rel
|
||||
userinterface.rel
|
||||
powermgt.rel
|
||||
barcode.rel
|
||||
i2cdevices.rel
|
||||
settings.rel
|
||||
soc/zbs243/soc.rel
|
||||
soc/zbs243/wdt.rel
|
||||
soc/zbs243/sleep.rel
|
||||
soc/zbs243/spi.rel
|
||||
soc/zbs243/uart.rel
|
||||
soc/zbs243/timer.rel
|
||||
soc/zbs243/radio.rel
|
||||
soc/zbs243/flash.rel
|
||||
soc/zbs243/temperature.rel
|
||||
cpu/8051/random.rel
|
||||
cpu/8051/printf.rel
|
||||
soc/zbs243/i2c.rel
|
||||
cpu/8051/asmUtil.rel
|
||||
cpu/8051/cpu.rel
|
||||
board/zbs29_uc8151/board.rel
|
||||
board/zbs29_uc8151/screen.rel
|
||||
|
||||
-e
|
||||
@@ -34,7 +34,7 @@ uint8_t __xdata wakeUpReason = 0;
|
||||
uint8_t __xdata scanAttempts = 0;
|
||||
|
||||
int8_t __xdata temperature = 0;
|
||||
uint16_t __xdata batteryVoltage = 0;
|
||||
uint16_t __xdata batteryVoltage = 2600;
|
||||
bool __xdata lowBattery = false;
|
||||
uint16_t __xdata longDataReqCounter = 0;
|
||||
uint16_t __xdata voltageCheckCounter = 0;
|
||||
@@ -153,10 +153,11 @@ static void configI2C(const bool setup) {
|
||||
if (setup) {
|
||||
P1DIR &= ~(1 << 6);
|
||||
P1_6 = 1;
|
||||
timerDelay(13330);
|
||||
P1FUNC |= (1 << 4) | (1 << 5);
|
||||
P1PULL |= (1 << 4) | (1 << 5);
|
||||
i2cInit();
|
||||
i2cCheckDevice(0x50); // first transaction after init fails, this makes sure everything is ready for the first transaction
|
||||
// i2cCheckDevice(0x50); // first transaction after init fails, this makes sure everything is ready for the first transaction
|
||||
} else {
|
||||
P1DIR |= (1 << 6);
|
||||
P1_6 = 0;
|
||||
@@ -174,6 +175,7 @@ void powerUp(const uint8_t parts) {
|
||||
timerInit();
|
||||
irqsOn();
|
||||
wdtOn();
|
||||
wdt10s();
|
||||
}
|
||||
|
||||
if (parts & INIT_EPD) {
|
||||
@@ -186,7 +188,7 @@ void powerUp(const uint8_t parts) {
|
||||
epdConfigGPIO(true);
|
||||
configSPI(true);
|
||||
batteryVoltage = epdGetBattery();
|
||||
if (batteryVoltage < BATTERY_VOLTAGE_MINIMUM) {
|
||||
if (batteryVoltage < tagSettings.batLowVoltage) {
|
||||
lowBattery = true;
|
||||
} else {
|
||||
lowBattery = false;
|
||||
@@ -302,7 +304,12 @@ void doSleep(const uint32_t __xdata t) {
|
||||
P1CHSTA &= ~(1 << 3);
|
||||
}
|
||||
|
||||
// sleepy
|
||||
if (tagSettings.enableRFWake) {
|
||||
// enabled RF wake, adds a little extra energy draw!
|
||||
RADIO_RadioPowerCtl &= 0xFB;
|
||||
}
|
||||
|
||||
// sleepy time
|
||||
sleepForMsec(t);
|
||||
P1INTEN = 0;
|
||||
if ((P1CHSTA & (1 << 0)) && (capabilities & CAPABILITY_HAS_WAKE_BUTTON)) {
|
||||
@@ -316,6 +323,12 @@ void doSleep(const uint32_t __xdata t) {
|
||||
}
|
||||
}
|
||||
|
||||
void doVoltageReading() {
|
||||
powerUp(INIT_RADIO); // load down the battery using the radio to get a good voltage reading
|
||||
powerUp(INIT_EPD_VOLTREADING | INIT_TEMPREADING);
|
||||
powerDown(INIT_RADIO);
|
||||
}
|
||||
|
||||
uint32_t getNextScanSleep(const bool increment) {
|
||||
if (increment) {
|
||||
if (scanAttempts < 255)
|
||||
@@ -346,5 +359,8 @@ uint16_t getNextSleep() {
|
||||
avg += dataReqAttemptArr[c];
|
||||
}
|
||||
avg /= POWER_SAVING_SMOOTHING;
|
||||
|
||||
// check if we should sleep longer due to an override in the config
|
||||
if (avg < tagSettings.minimumCheckInTime) return tagSettings.minimumCheckInTime;
|
||||
return avg;
|
||||
}
|
||||
@@ -55,6 +55,8 @@ extern void powerDown(const uint8_t parts);
|
||||
extern void initAfterWake();
|
||||
extern void doSleep(const uint32_t __xdata t);
|
||||
|
||||
void doVoltageReading();
|
||||
|
||||
extern void addAverageValue();
|
||||
extern uint16_t getNextSleep();
|
||||
|
||||
|
||||
95
zbs243_Tag_FW/settings.c
Executable file
95
zbs243_Tag_FW/settings.c
Executable file
@@ -0,0 +1,95 @@
|
||||
#include "settings.h"
|
||||
|
||||
#include <flash.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asmUtil.h"
|
||||
#include "powermgt.h"
|
||||
#include "printf.h"
|
||||
#include "syncedproto.h"
|
||||
|
||||
struct tagsettings __xdata tagSettings = {0};
|
||||
extern uint8_t __xdata blockXferBuffer[];
|
||||
uint8_t* __xdata infopageTempBuffer = 1024 + blockXferBuffer;
|
||||
|
||||
#define INFOPAGE_SETTINGS_OFFSET 0x50
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
void loadSettingsFromBuffer(uint8_t* p) {
|
||||
pr("SETTINGS: received settings from AP\n");
|
||||
switch (*p) {
|
||||
case SETTINGS_STRUCT_VERSION: // the current tag struct
|
||||
pr("SETTINGS: received matching version\n");
|
||||
memcpy((void*)tagSettings, (void*)p, sizeof(struct tagsettings));
|
||||
break;
|
||||
default:
|
||||
pr("SETTINGS: received something we couldn't really process, version %d\n");
|
||||
break;
|
||||
}
|
||||
tagSettings.fastBootCapabilities = capabilities;
|
||||
writeSettings();
|
||||
}
|
||||
|
||||
static bool compareSettings() {
|
||||
// check if the settings match the settings in the infopage
|
||||
flashRead(FLASH_INFOPAGE_ADDR + INFOPAGE_SETTINGS_OFFSET, (void*)infopageTempBuffer, sizeof(struct tagsettings));
|
||||
if (memcmp((void*)infopageTempBuffer, (void*)tagSettings, sizeof(struct tagsettings)) == 0) {
|
||||
// same
|
||||
return true;
|
||||
}
|
||||
// different
|
||||
return false;
|
||||
}
|
||||
|
||||
static void upgradeSettings() {
|
||||
// add an upgrade strategy whenever you update the struct version
|
||||
}
|
||||
|
||||
void loadSettings() {
|
||||
flashRead((FLASH_INFOPAGE_ADDR + INFOPAGE_SETTINGS_OFFSET), (void*)infopageTempBuffer, sizeof(struct tagsettings));
|
||||
xMemCopy((void*)tagSettings, (void*)infopageTempBuffer, sizeof(struct tagsettings));
|
||||
if (tagSettings.settingsVer == 0xFF) {
|
||||
// settings not set. load the defaults
|
||||
loadDefaultSettings();
|
||||
pr("SETTINGS: Loaded default settings\n");
|
||||
} else {
|
||||
if (tagSettings.settingsVer < SETTINGS_STRUCT_VERSION) {
|
||||
// upgrade
|
||||
upgradeSettings();
|
||||
pr("SETTINGS: Upgraded from previous version\n");
|
||||
} else {
|
||||
// settings are valid
|
||||
pr("SETTINGS: Loaded from infopage\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void writeSettings() {
|
||||
if (compareSettings()) {
|
||||
pr("SETTINGS: Settings matched current settings\n");
|
||||
return;
|
||||
}
|
||||
flashRead(FLASH_INFOPAGE_ADDR, (void*)infopageTempBuffer, 1024);
|
||||
xMemCopy((void*)(infopageTempBuffer + INFOPAGE_SETTINGS_OFFSET), (void*)tagSettings, sizeof(tagSettings));
|
||||
flashErase(FLASH_INFOPAGE_ADDR + 1);
|
||||
flashWrite(FLASH_INFOPAGE_ADDR, (void*)infopageTempBuffer, 1024, false);
|
||||
pr("SETTINGS: Updated settings in infopage\n");
|
||||
}
|
||||
@@ -3,8 +3,39 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define FW_VERSION 017 // version number (max 2.5.5 :) )
|
||||
#define FW_VERSION_SUFFIX "-CLUT" // suffix, like -RC1 or whatever.
|
||||
#define FW_VERSION 18 // version number (max 2.5.5 :) )
|
||||
#define FW_VERSION_SUFFIX "-RW" // 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 SETTINGS_STRUCT_VERSION 0x01
|
||||
|
||||
#define DEFAULT_SETTING_FASTBOOT 0
|
||||
#define DEFAULT_SETTING_RFWAKE 0
|
||||
#define DEFAULT_SETTING_TAGROAMING 0
|
||||
#define DEFAULT_SETTING_SCANFORAP 1
|
||||
#define DEFAULT_SETTING_LOWBATSYMBOL 1
|
||||
#define DEFAULT_SETTING_NORFSYMBOL 1
|
||||
|
||||
struct tagsettings {
|
||||
uint8_t settingsVer; // the version of the struct as written to the infopage
|
||||
uint8_t enableFastBoot; // default 0; if set, it will skip splashscreen
|
||||
uint8_t enableRFWake; // default 0; if set, it will enable RF wake. This will add about ~0.9µA idle power consumption
|
||||
uint8_t enableTagRoaming; // default 0; if set, the tag will scan for an accesspoint every few check-ins. This will increase power consumption quite a bit
|
||||
uint8_t enableScanForAPAfterTimeout; // default 1; if a the tag failed to check in, after a few attempts it will try to find a an AP on other channels
|
||||
uint8_t enableLowBatSymbol; // default 1; tag will show 'low battery' icon on screen if the battery is depleted
|
||||
uint8_t enableNoRFSymbol; // default 1; tag will show 'no signal' icon on screen if it failed to check in for a longer period of time
|
||||
uint8_t fastBootCapabilities; // holds the byte with 'capabilities' as detected during a normal tag boot; allows the tag to skip detecting buttons and NFC chip
|
||||
uint8_t customMode; // default 0; if anything else, tag will bootup in a different 'mode'
|
||||
uint16_t batLowVoltage; // Low battery threshold voltage (2450 for 2.45v). defaults to BATTERY_VOLTAGE_MINIMUM from powermgt.h
|
||||
uint16_t minimumCheckInTime; // defaults to BASE_INTERVAL from powermgt.h
|
||||
uint8_t fixedChannel; // default 0; if set to a valid channel number, the tag will stick to that channel
|
||||
} __packed;
|
||||
|
||||
extern struct tagsettings tagSettings;
|
||||
|
||||
void loadDefaultSettings();
|
||||
void writeSettings();
|
||||
void loadSettings();
|
||||
void loadSettingsFromBuffer(uint8_t* p);
|
||||
#endif
|
||||
@@ -50,6 +50,8 @@ uint8_t __xdata currentChannel = 0;
|
||||
static uint8_t __xdata inBuffer[128] = {0};
|
||||
static uint8_t __xdata outBuffer[128] = {0};
|
||||
|
||||
extern void executeCommand(uint8_t cmd); // this is defined in main.c
|
||||
|
||||
// tools
|
||||
static uint8_t __xdata getPacketType(const void *__xdata buffer) {
|
||||
const struct MacFcs *__xdata fcs = buffer;
|
||||
@@ -471,6 +473,7 @@ static uint32_t getHighSlotId() {
|
||||
return temp;
|
||||
}
|
||||
|
||||
// data transfer stuff
|
||||
static uint8_t __xdata partsThisBlock = 0;
|
||||
static uint8_t __xdata blockAttempts = 0; // these CAN be local to the function, but for some reason, they won't survive sleep?
|
||||
// they get overwritten with 7F 32 44 20 00 00 00 00 11, I don't know why.
|
||||
@@ -570,6 +573,7 @@ static bool getDataBlock(const uint16_t blockSize) {
|
||||
pr("failed getting block\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t __xdata dataRequestSize = 0;
|
||||
static bool downloadFWUpdate(const struct AvailDataInfo *__xdata avail) {
|
||||
// check if we already started the transfer of this information & haven't completed it
|
||||
@@ -847,6 +851,37 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) {
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
case DATATYPE_TAG_CONFIG_DATA:
|
||||
if (curDataInfo.dataSize == 0 && xMemEqual((const void *__xdata) & avail->dataVer, (const void *__xdata) & curDataInfo.dataVer, 8)) {
|
||||
pr("this was the same as the last transfer, disregard\n");
|
||||
powerUp(INIT_RADIO);
|
||||
sendXferComplete();
|
||||
powerDown(INIT_RADIO);
|
||||
return true;
|
||||
}
|
||||
curBlock.blockId = 0;
|
||||
xMemCopy8(&(curBlock.ver), &(avail->dataVer));
|
||||
curBlock.type = avail->dataType;
|
||||
xMemCopyShort(&curDataInfo, (void *)avail, sizeof(struct AvailDataInfo));
|
||||
wdt10s();
|
||||
if (getDataBlock(avail->dataSize)) {
|
||||
curDataInfo.dataSize = 0; // mark as transfer not pending
|
||||
loadSettingsFromBuffer(sizeof(struct blockData) + blockXferBuffer);
|
||||
powerUp(INIT_RADIO);
|
||||
sendXferComplete();
|
||||
powerDown(INIT_RADIO);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
break;
|
||||
case DATATYPE_COMMAND_DATA:
|
||||
pr("CMD received\n");
|
||||
powerUp(INIT_RADIO);
|
||||
sendXferComplete();
|
||||
powerDown(INIT_RADIO);
|
||||
executeCommand(avail->dataTypeArgument);
|
||||
return true;
|
||||
break;
|
||||
case DATATYPE_CUSTOM_LUT_OTA:
|
||||
// Handle data for the NFC IC (if we have it)
|
||||
|
||||
@@ -874,7 +909,7 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) {
|
||||
wdt10s();
|
||||
if (getDataBlock(avail->dataSize)) {
|
||||
curDataInfo.dataSize = 0; // mark as transfer not pending
|
||||
memcpy(customLUT, sizeof(struct blockData) + blockXferBuffer, dispLutSize * 10);
|
||||
memcpy(customLUT, sizeof(struct blockData) + blockXferBuffer, 6 + (dispLutSize * 10));
|
||||
powerUp(INIT_RADIO);
|
||||
sendXferComplete();
|
||||
powerDown(INIT_RADIO);
|
||||
@@ -888,6 +923,8 @@ bool processAvailDataInfo(struct AvailDataInfo *__xdata avail) {
|
||||
}
|
||||
|
||||
void initializeProto() {
|
||||
powerUp(INIT_EEPROM);
|
||||
getNumSlots();
|
||||
curHighSlotId = getHighSlotId();
|
||||
powerDown(INIT_EEPROM);
|
||||
}
|
||||
2
zbs243_Tag_FW/syncedproto.h
Normal file → Executable file
2
zbs243_Tag_FW/syncedproto.h
Normal file → Executable file
@@ -13,7 +13,7 @@ extern uint8_t __xdata curImgSlot;
|
||||
extern void setupRadio(void);
|
||||
extern void killRadio(void);
|
||||
|
||||
|
||||
void dump(const uint8_t *__xdata a, const uint16_t __xdata l);
|
||||
extern struct AvailDataInfo *__xdata getAvailDataInfo();
|
||||
extern struct AvailDataInfo *__xdata getShortAvailDataInfo();
|
||||
extern void drawImageFromEeprom(const uint8_t imgSlot);
|
||||
|
||||
@@ -51,7 +51,7 @@ void addCapabilities() {
|
||||
}
|
||||
|
||||
void addOverlay() {
|
||||
if (currentChannel == 0) {
|
||||
if ((currentChannel == 0)&&(tagSettings.enableNoRFSymbol)) {
|
||||
#if (SCREEN_WIDTH == 152)
|
||||
loadRawBitmap(ant, SCREEN_WIDTH - 16, 0, EPD_COLOR_BLACK);
|
||||
loadRawBitmap(cross, SCREEN_WIDTH - 8, 7, EPD_COLOR_RED);
|
||||
@@ -67,7 +67,7 @@ void addOverlay() {
|
||||
noAPShown = false;
|
||||
}
|
||||
|
||||
if (batteryVoltage != 2600) {
|
||||
if ((batteryVoltage < tagSettings.batLowVoltage) && (tagSettings.enableLowBatSymbol)) {
|
||||
#if (SCREEN_WIDTH == 152)
|
||||
loadRawBitmap(battery, SCREEN_WIDTH - 16, SCREEN_HEIGHT - 10, EPD_COLOR_BLACK);
|
||||
#elif (SCREEN_WIDTH == 400)
|
||||
@@ -81,7 +81,6 @@ void addOverlay() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void afterFlashScreenSaver() {
|
||||
selectLUT(EPD_LUT_DEFAULT);
|
||||
clearScreen();
|
||||
@@ -106,7 +105,6 @@ void afterFlashScreenSaver() {
|
||||
drawWithSleep();
|
||||
}
|
||||
|
||||
|
||||
void showSplashScreen() {
|
||||
selectLUT(EPD_LUT_NO_REPEATS);
|
||||
clearScreen();
|
||||
|
||||
@@ -42,6 +42,11 @@
|
||||
#define CMD_YSTART_POS 0x4F
|
||||
#define CMD_ANALOG_BLK_CTRL 0x74
|
||||
#define CMD_DIGITAL_BLK_CTRL 0x7E
|
||||
// added for OTA LUT-support
|
||||
#define CMD_GATE_LEVEL 0x03
|
||||
#define CMD_SOURCE_LEVEL 0x04
|
||||
#define CMD_DUMMY_PERIOD 0x3A
|
||||
#define CMD_GATE_LINE_WIDTH 0x3B
|
||||
|
||||
#define SCREEN_CMD_CLOCK_ON 0x80
|
||||
#define SCREEN_CMD_CLOCK_OFF 0x01
|
||||
@@ -83,7 +88,7 @@ bool __xdata epdGPIOActive = false;
|
||||
|
||||
#define LUT_BUFFER_SIZE 128
|
||||
static uint8_t waveformbuffer[LUT_BUFFER_SIZE];
|
||||
uint8_t __xdata customLUT[LUT_BUFFER_SIZE] = {0};
|
||||
uint8_t __xdata customLUT[LUT_BUFFER_SIZE] = {0};
|
||||
|
||||
struct waveform10* __xdata waveform10 = (struct waveform10*)waveformbuffer; // holds the LUT/waveform
|
||||
struct waveform* __xdata waveform7 = (struct waveform*)waveformbuffer; // holds the LUT/waveform
|
||||
@@ -378,14 +383,6 @@ void selectLUT(uint8_t lut) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Handling if we received an OTA LUT
|
||||
if (lut == EPD_LUT_OTA) {
|
||||
memcpy(waveformbuffer, customLUT, dispLutSize * 10);
|
||||
writeLut();
|
||||
currentLut = lut;
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentLut != EPD_LUT_DEFAULT) {
|
||||
// load the 'default' LUT for the current temperature in the EPD lut register
|
||||
shortCommand1(CMD_DISP_UPDATE_CTRL2, 0xB1); // mode 1?
|
||||
@@ -447,6 +444,22 @@ void selectLUT(uint8_t lut) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Handling if we received an OTA LUT
|
||||
if (lut == EPD_LUT_OTA) {
|
||||
memcpy(waveformbuffer, customLUT, dispLutSize * 10);
|
||||
writeLut();
|
||||
shortCommand1(CMD_GATE_LEVEL, customLUT[70]);
|
||||
commandBegin(CMD_SOURCE_LEVEL);
|
||||
epdSend(customLUT[71]);
|
||||
epdSend(customLUT[72]);
|
||||
epdSend(customLUT[73]);
|
||||
commandEnd();
|
||||
shortCommand1(CMD_DUMMY_PERIOD, customLUT[74]);
|
||||
shortCommand1(CMD_GATE_LINE_WIDTH, customLUT[75]);
|
||||
currentLut = lut;
|
||||
return;
|
||||
}
|
||||
|
||||
if (dispLutSize == 10) {
|
||||
lutGroupDisable(LUTGROUP_UNUSED);
|
||||
lutGroupDisable(LUTGROUP_UNKNOWN);
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#define HAS_EEPROM 1
|
||||
#define HAS_SCREEN 1
|
||||
#define NFC_TYPE 1
|
||||
#define AP_EMULATE_TAG 1
|
||||
|
||||
//hw types
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#define HAS_EEPROM 1
|
||||
#define HAS_SCREEN 1
|
||||
#define NFC_TYPE 1
|
||||
#define AP_EMULATE_TAG 1
|
||||
|
||||
//hw types
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#define HAS_EEPROM 1
|
||||
#define HAS_SCREEN 1
|
||||
#define NFC_TYPE 1
|
||||
#define AP_EMULATE_TAG 1
|
||||
|
||||
//hw types
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#define HAS_EEPROM 1
|
||||
#define HAS_SCREEN 1
|
||||
#define NFC_TYPE 2
|
||||
#define AP_EMULATE_TAG 1
|
||||
|
||||
//hw types
|
||||
|
||||
Reference in New Issue
Block a user