Added the tag-flasher

This commit is contained in:
Jelmer
2023-08-24 21:37:32 +02:00
parent 891b7a83be
commit 3c77e375d9
25 changed files with 2837 additions and 336 deletions

View File

@@ -1,318 +0,0 @@
import argparse
import serial.tools.list_ports
import serial
import time
from intelhex import IntelHex
import os.path
CMD_GET_VERSION = 1
CMD_RESET_ESP = 2
CMD_RESET = 11
CMD_SET_POWER = 13
CMD_ERASE_FLASH = 26
CMD_ERASE_INFOPAGE = 27
CMD_SAVE_MAC_FROM_FW = 40
CMD_PASS_THROUGH = 50
CMD_SELECT_ZBS243 = 60
CMD_SELECT_NRF82511 = 61
CMD_SELECT_PORT = 70
CMD_READ_INFOPAGE = 80
CMD_READ_FLASH = 81
CMD_WRITE_INFOPAGE = 82
CMD_WRITE_FLASH = 83
CMD_AUTOFLASH = 87
CMD_COMPLETE = 88
def read_binary_file(file_path):
with open(file_path, 'rb') as file:
binary_data = file.read()
return binary_data
def read_hex_file(file_path):
ih = IntelHex(file_path)
binary_data = ih.tobinarray()
return bytes(binary_data)
def to_byte(input, number=4):
return input.to_bytes(number, byteorder='big')
def send_cmd(cmd, data):
return_data = to_byte(cmd, 1) + to_byte(len(data), 4) + data
crc_val = 0xAB34
for x in return_data:
crc_val += x
return_data = b"AT" + return_data + to_byte(crc_val & 0xffff, 2)
ser.write(return_data)
def wait_for_command():
start_time = time.time()
ser.timeout = 5 # Set the timeout to 1 second
while True:
if ser.in_waiting > 0:
command = ser.read(2) # Read the "AT" prefix
if command == b"AT":
# Read the command byte
cmd = int.from_bytes(ser.read(1), byteorder='big')
data_length = int.from_bytes(
ser.read(4), byteorder='big') # Read the data length
data = ser.read(data_length) # Read the data
# Read the CRC value
crc = int.from_bytes(ser.read(2), byteorder='big')
# Verify CRC
crc_val = 0xAB34
for x in to_byte(cmd, 1) + to_byte(data_length, 4) + data:
crc_val += x
if crc_val & 0xffff == crc:
return cmd, data
else:
print("Invalid CRC. Discarding command. Got " +
str(crc_val) + " but was expecting "+str(crc))
print("data was:"+str(data))
if time.time() - start_time > ser.timeout:
print("timeout waiting for reply")
return None, None
def list_available_com_ports():
ports = serial.tools.list_ports.comports()
available_ports = [port.device for port in ports]
print("Specify a serial port to use with -p <PORT>")
print("available COM ports:")
for port in available_ports:
print(port)
def validate_arguments(args):
if not (args.nrf82511 or args.zbs243):
print("Either -nrf82511 or -zbs243 option is required.")
return False
if not (args.internalap or args.external or args.altradio):
print("One of -internalap, -external, or -altradio options is required.")
return False
if args.command in ["read", "write"] and not (args.flash or args.infopage):
print("One of --flash or --infopage arguments is required for read and write commands.")
return False
if ((args.command == "debug" or args.pt) and not (args.external)):
print("Debugging/Passthrough is only available on the external port!")
return False
if args.command == "write" and not os.path.isfile(args.filename):
print("Couldn't find the specified file!")
return False;
if args.command in ["read", "write"] and not args.filename:
print("Please specify a file to save read data")
return False;
if args.command == "read" and len(args.filename) < 2:
print("Please specify a file to save read data")
return False;
return True
def read_from_serial(port, filename, flash):
if flash:
print(
f"Reading flash data and saving to file: {filename}.")
else:
print(
f"Reading info page and saving to file: {filename}.")
print("Now downloading...\n")
file = open(filename, "wb")
bytecount = 0
while True:
print(f'\r{bytecount} bytes', end='', flush=True)
if (flash):
send_cmd(CMD_READ_FLASH, bytearray([]))
else:
send_cmd(CMD_READ_INFOPAGE, bytearray([]))
cmd, answer = wait_for_command()
if ((cmd == CMD_READ_FLASH) or (cmd == CMD_READ_INFOPAGE)):
file.write(bytearray(answer))
bytecount += len(answer)
elif (cmd == CMD_COMPLETE):
file.close()
print("\r All done! \nFile saved\n", end='', flush=True)
break
else:
print("Failed reading block, timeout?")
def write_to_serial(port, filename, flash):
if flash:
print(f"\nErasing flash... ")
send_cmd(CMD_ERASE_FLASH, bytearray([]))
else:
print(f"\nErasing infopage... ")
send_cmd(CMD_ERASE_INFOPAGE, bytearray([]))
cmd, answer = wait_for_command()
if ((cmd == CMD_ERASE_FLASH) or (cmd == CMD_ERASE_INFOPAGE)):
print("DONE!\n")
else:
print("\nFailed to erase the flash?")
exit(0)
# TODO: Implement logic to write data from the file to the serial port with flash option
if flash:
print(f"Writing flash data from file: {filename}\n")
else:
print(f"Writing info page data from file: {filename}\n")
chunk_size = 1024
if filename.endswith('.bin'):
file_data = read_binary_file(filename)
elif filename.endswith('.hex'):
file_data = read_hex_file(filename)
for i in range(0, len(file_data), chunk_size):
chunk = file_data[i:i + chunk_size]
if (flash):
send_cmd(CMD_WRITE_FLASH, bytearray(chunk))
else:
send_cmd(CMD_WRITE_INFOPAGE, bytearray(chunk))
cmd, answer = wait_for_command()
if ((cmd == CMD_WRITE_FLASH) or (cmd == CMD_WRITE_INFOPAGE)):
print(f'\rSent {i} bytes', end='', flush=True)
elif (cmd == CMD_COMPLETE):
print(
'\Tried to write more bytes than we have room for! \n', end='', flush=True)
return
else:
print("Some other error, dunno\n")
return
print('\rAll done writing! ', end='', flush=True)
def short_passthough(period_time):
start_time = time.time()
while time.time() - start_time < period_time:
data = ser.read()
if data:
print(data.decode(), end='')
if chr(0x04) in data.decode():
break
def main():
try:
parser = argparse.ArgumentParser(
description="OpenEPaperLink Flasher for AP/Flasher board")
parser.add_argument("-p", "--port", help="COM port to use")
parser.add_argument("command", choices=[
"read", "write", "autoflash", "debug"], help="Command to execute")
parser.add_argument("filename", nargs="?",
help="Filename for read/write commands")
parser.add_argument("-f", "--flash", action="store_true",
help="Write to the flash")
parser.add_argument("-i", "--infopage", action="store_true",
help="Write to the infopage/UICR")
parser.add_argument("-n", "--nrf82511", action="store_true",
help="nRF82511 programming")
parser.add_argument("-z", "--zbs243", action="store_true",
help="ZBS243 programming")
parser.add_argument("--internalap", action="store_true",
help="Selects the internal accesspoint port")
parser.add_argument("-e", "--external", action="store_true",
help="Selects the external(side) port")
parser.add_argument("--altradio", action="store_true",
help="Selects the alternate radio port")
parser.add_argument("--pt","--passthrough", action="store_true",
help="Enters serial passthrough for debug output after flashing")
args = parser.parse_args()
if not validate_arguments(args):
return
if not args.port:
list_available_com_ports()
return
global ser
ser = serial.Serial(args.port, baudrate=500000)
time.sleep(1) # Flush serial data
while (ser.inWaiting() > 0):
data_str = ser.read(ser.inWaiting())
send_cmd(CMD_GET_VERSION, bytearray([]))
cmd, answer = wait_for_command()
if (cmd == CMD_GET_VERSION):
print("AP/Flasher version: " +
str(answer[0] << 24 | answer[1] << 16 | answer[2] << 8 | answer[3]))
else:
print(
"Couldn't establish a connection with the flasher, did you select the correct serial port?")
exit(0)
if (args.command!="debug"):
if args.internalap:
send_cmd(CMD_SELECT_PORT, bytearray([0]))
if args.external:
send_cmd(CMD_SELECT_PORT, bytearray([1]))
if args.altradio:
send_cmd(CMD_SELECT_PORT, bytearray([2]))
if args.nrf82511:
send_cmd(CMD_SELECT_NRF82511, bytearray([]))
if args.zbs243:
send_cmd(CMD_SELECT_ZBS243, bytearray([]))
cmd, answer = wait_for_command()
if (answer[0] == 1):
print("Connection established to microcontroller")
else:
print("Failed to establish a connection to the microcontroller")
exit(0)
if args.command == "read":
read_from_serial(ser, args.filename, args.flash)
elif args.command == "write":
write_to_serial(ser, args.filename, args.flash)
elif args.command == "autoflash":
print("Starting automatic tag flash")
send_cmd(CMD_AUTOFLASH , bytearray([]))
short_passthough(30)
else:
print("Invalid command!")
send_cmd(CMD_RESET, bytearray([]))
cmd, answer = wait_for_command()
send_cmd(CMD_SET_POWER, bytearray([1]))
cmd, answer = wait_for_command()
if (args.pt or args.command=="debug"):
# enter passthrough mode
send_cmd(CMD_PASS_THROUGH , bytearray([]))
print("Now showing debug output from the tag - CTRL+C to quit");
print("---------------------------------------------------------------------------------");
while True:
try:
data = ser.read()
if data:
print(data.decode('utf-8', errors='replace'), end='')
except UnicodeDecodeError:
print(" ")
data = ser.read()
if data:
print(data.decode(), end='')
if chr(0x04) in data.decode():
break
except KeyboardInterrupt:
print("\nBye!")
ser.close()
exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,4 @@
Language: Cpp
BasedOnStyle: Google
IndentWidth: 4
ColumnLimit: 0

5
Tag_Flasher/ESP32_Flasher/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

View File

@@ -0,0 +1,10 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
],
"unwantedRecommendations": [
"ms-vscode.cpptools-extension-pack"
]
}

View File

@@ -0,0 +1,55 @@
{
"C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: Google, IndentWidth: 4, ColumnLimit: 0}",
"files.associations": {
"array": "cpp",
"atomic": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"map": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"regex": "cpp",
"string": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"istream": "cpp",
"limits": "cpp",
"new": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp"
}
}

View File

@@ -0,0 +1,3 @@
cmake_minimum_required(VERSION 3.16.0)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp32_fw)

View File

@@ -0,0 +1,59 @@
#include <Arduino.h>
#include <LittleFS.h>
void flashCountDown(uint8_t c);
#ifdef OPENEPAPERLINK_PCB
bool extTagConnected();
bool doTagFlash();
#endif
class flasher {
public:
class ZBS_interface *zbs = nullptr;
uint8_t md5[16] = {0};
char md5char[34];
uint8_t tagtype;
uint8_t *infoblock = nullptr;
// Infoblock structure:
// 0x00-0x0F - Calibration data
// 0x10-0x17 - MAC
// 0x19 - OpenEPaperLink Type
// 0x30 - Original firmware MD5
uint8_t mac[8] = {0};
uint8_t mac_format = 0;
uint16_t mac_suffix = 0;
uint16_t mac_offset = 0;
flasher();
~flasher();
bool connectTag(uint8_t port);
void getFirmwareMD5();
bool getFirmwareMac();
bool findTagByMD5();
bool findTagByType(uint8_t type);
bool getInfoBlockMD5();
bool getInfoBlockMac();
bool getInfoBlockType();
void getMacFromWiFi();
bool prepareInfoBlock();
bool backupFlash();
bool writeFlash(uint8_t *flashbuffer, uint16_t size);
bool writeFlashFromPack(String filename, uint8_t type);
bool writeFlashFromPackOffset(fs::File *file, uint16_t length);
bool readBlock(uint16_t offset, uint8_t* data, uint16_t len, bool infopage);
bool writeBlock(uint16_t offset, uint8_t* data, uint16_t len, bool infopage);
bool readInfoBlock();
bool writeInfoBlock();
protected:
bool writeBlock256(uint16_t offset, uint8_t *flashbuffer);
void get_mac_format1();
void get_mac_format2();
};

View File

@@ -0,0 +1,37 @@
#include <Arduino.h>
#ifdef HAS_RGB_LED
#define FASTLED_INTERNAL
#include <FastLED.h>
#endif
const uint8_t PROGMEM gamma8[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5,
5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10,
10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16,
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25,
25, 26, 27, 27, 28, 29, 29, 30, 31, 32, 32, 33, 34, 35, 35, 36,
37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 50,
51, 52, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 66, 67, 68,
69, 70, 72, 73, 74, 75, 77, 78, 79, 81, 82, 83, 85, 86, 87, 89,
90, 92, 93, 95, 96, 98, 99, 101, 102, 104, 105, 107, 109, 110, 112, 114,
115, 117, 119, 120, 122, 124, 126, 127, 129, 131, 133, 135, 137, 138, 140, 142,
144, 146, 148, 150, 152, 154, 156, 158, 160, 162, 164, 167, 169, 171, 173, 175,
177, 180, 182, 184, 186, 189, 191, 193, 196, 198, 200, 203, 205, 208, 210, 213,
215, 218, 220, 223, 225, 228, 231, 233, 236, 239, 241, 244, 247, 249, 252, 255};
void ledTask(void* parameter);
void setBrightness(int brightness);
void updateBrightnessFromConfig();
#ifdef HAS_RGB_LED
void shortBlink(CRGB cname);
void showColorPattern(CRGB colorone, CRGB colortwo, CRGB colorthree);
void rgbIdle();
void addFadeColor(CRGB cname);
#endif
void quickBlink(uint8_t repeat);

View File

@@ -0,0 +1,5 @@
#include <Arduino.h>
//void doLeds();
void powerControl(bool powerState, uint8_t* pin, uint8_t pincount);

View File

@@ -0,0 +1,9 @@
#include <Arduino.h>
#define FLASHER_EXT_PORT 1
// flasher options
#define CUSTOM_MAC_HDR 0x0000
#define MAX_WRITE_ATTEMPTS 5

View File

@@ -0,0 +1,42 @@
#ifndef _DYN_STORAGE_H_
#define _DYN_STORAGE_H_
#include "FS.h"
#ifdef HAS_SDCARD
#ifndef SD_CARD_SS
#error SD_CARD_SS UNDEFINED
#endif
#ifndef SD_CARD_CLK
#define SD_CARD_CLK 18
#endif
#ifndef SD_CARD_MISO
#define SD_CARD_MISO 19
#endif
#ifndef SD_CARD_MOSI
#define SD_CARD_MOSI 23
#endif
#endif
class DynStorage {
public:
DynStorage();
void begin();
void end();
void listFiles();
size_t freeSpace();
private:
bool isInited;
};
extern DynStorage Storage;
extern fs::FS *contentFS;
extern void copyFile(File in, File out);
#endif

View File

@@ -0,0 +1,83 @@
#include <Arduino.h>
#include <stdint.h>
/*
Copyright (c) 2021 Aaron Christophel ATCnetz.de
SPDX-License-Identifier: GPL-3.0-or-later
*/
#pragma once
class swd {
public:
swd(uint8_t swdio, uint8_t swdclk);
uint32_t swd_Init();
bool AP_Write(unsigned addr, uint32_t data);
bool AP_Read(unsigned addr, uint32_t &data);
bool DP_Write(unsigned addr, uint32_t data);
bool DP_Read(unsigned addr, uint32_t &data);
uint32_t idCode;
protected:
void swd_Begin();
void swd_Direction(bool WorR);
bool swd_Transfer(unsigned port_address, bool APorDP, bool RorW, uint32_t &data);
bool calculate_Parity(uint32_t in_data);
void swd_Write(uint32_t in_data, uint8_t bits);
uint32_t swd_Read(uint8_t bits);
uint8_t swdio_pin;
uint8_t swdclk_pin;
bool cur_swd_direction = 0;
};
struct nrf_info_struct {
int flash_size;
uint32_t connected;
uint32_t codepage_size;
uint32_t codesize;
uint32_t config_id;
uint32_t device_id0;
uint32_t device_id1;
uint32_t info_part;
uint32_t info_variant;
uint32_t info_package;
uint16_t sd_info_area;
uint32_t ucir_lock;
};
class nrfswd : protected swd {
public:
nrfswd(uint8_t swdio, uint8_t swdclk);
bool init();
uint8_t nrf_read_bank(uint32_t address, uint32_t buffer[], int size);
uint8_t nrf_write_bank(uint32_t address, uint32_t buffer[], int size);
uint8_t erase_all_flash();
uint8_t erase_uicr();
uint8_t erase_page(uint32_t page);
void nrf_soft_reset();
bool isConnected = false;
bool isLocked = false;
bool showDebug = true;
struct nrf_info_struct nrf_info;
protected:
uint32_t nrf_read_port(bool APorDP, uint8_t address);
void nrf_write_port(bool APorDP, uint8_t address, uint32_t value);
void nrf_abort_all();
void nrf_halt();
void nrf_port_selection(bool new_port);
bool nrf_read_lock_state();
void nrf_read_ufcr();
void write_register(uint32_t address, uint32_t value);
uint32_t read_register(uint32_t address);
};

View File

@@ -0,0 +1,4 @@
#include <Arduino.h>
void usbFlasherTask(void* parameter);

View File

@@ -0,0 +1,64 @@
#pragma once
#include <stdio.h>
#include <stdint.h>
#include <SPI.h>
/* Autor: Aaron Christophel ATCnetz.de */
#include <Arduino.h>
class ZBS_interface
{
public:
uint8_t begin(uint8_t SS, uint8_t CLK, uint8_t MOSI, uint8_t MISO, uint8_t RESET, uint8_t* POWER, uint8_t powerPins, uint32_t spi_speed = 8000000);
void setSpeed(uint32_t speed);
void set_power(uint8_t state);
void enable_debug();
void reset();
void send_byte(uint8_t data);
uint8_t read_byte();
void write_byte(uint8_t cmd, uint8_t addr, uint8_t data);
uint8_t read_byte(uint8_t cmd, uint8_t addr);
void write_flash(uint16_t addr, uint8_t data);
uint8_t read_flash(uint16_t addr);
void write_ram(uint8_t addr, uint8_t data);
uint8_t read_ram(uint8_t addr);
void write_sfr(uint8_t addr, uint8_t data);
uint8_t read_sfr(uint8_t addr);
uint8_t check_connection();
uint8_t select_flash(uint8_t page);
void erase_flash();
void erase_infoblock();
~ZBS_interface();
private:
SPIClass *spi = NULL;
SPISettings spiSettings;
uint8_t _SS_PIN = -1;
uint8_t _CLK_PIN = -1;
uint8_t _MOSI_PIN = -1;
uint8_t _MISO_PIN = -1;
uint8_t _RESET_PIN = -1;
uint8_t* _POWER_PIN = nullptr;
uint8_t _POWER_PINS = 1;
int ZBS_spi_delay = 1;
uint8_t spi_ready = 0;
uint32_t after_byte_delay = 10;
typedef enum
{
ZBS_CMD_W_RAM = 0x02,
ZBS_CMD_R_RAM = 0x03,
ZBS_CMD_W_FLASH = 0x08,
ZBS_CMD_R_FLASH = 0x09,
ZBS_CMD_W_SFR = 0x12,
ZBS_CMD_R_SFR = 0x13,
ZBS_CMD_ERASE_FLASH = 0x88,
ZBS_CMD_ERASE_INFOBLOCK = 0x48,
} ZBS_CMD_LIST;
typedef enum
{
ZBS_ON = 1,
ZBS_OFF = 0,
} ZBS_POWER_STATE;
};

View File

@@ -0,0 +1,64 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env]
platform = espressif32
framework = arduino
lib_deps =
https://github.com/MajenkoLibraries/SoftSPI
bblanchon/ArduinoJson
platform_packages =
board_build.filesystem = littlefs
monitor_filters = esp32_exception_decoder
monitor_speed = 115200
board_build.f_cpu = 240000000L
build_flags =
-D BUILD_ENV_NAME=$PIOENV
-D BUILD_TIME=$UNIX_TIME
-D USER_SETUP_LOADED
-D DISABLE_ALL_LIBRARY_WARNINGS
; ----------------------------------------------------------------------------------------
; !!! this configuration expects the Mini_AP
;
; ----------------------------------------------------------------------------------------
[env:S2_Tag_Flasher]
platform = https://github.com/platformio/platform-espressif32.git
board=lolin_s2_mini
board_build.partitions = default.csv
build_unflags =
-D ARDUINO_USB_MODE=1
-D CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
build_flags =
${env.build_flags}
-D HAS_USB
-D OPENEPAPERLINK_NANO_AP_PCB
-D ARDUINO_USB_MODE=0
-D CONFIG_SPIRAM_USE_MALLOC=1
-D CONFIG_MBEDTLS_EXTERNAL_MEM_ALLOC=y
-D BOARD_HAS_PSRAM
-D FLASHER_EXT_SS=34
-D FLASHER_EXT_CLK=33
-D FLASHER_EXT_MOSI=37
-D FLASHER_EXT_MISO=35
-D FLASHER_EXT_RESET=39
-D FLASHER_EXT_POWER={16,17,18,21}
-D FLASHER_EXT_TXD=40
-D FLASHER_EXT_RXD=36
-D FLASHER_EXT_TEST=38
-D FLASHER_LED=15
build_src_filter =
+<*>-<ousbflasher.cpp>-<oswd.cpp>
board_build.psram_type=qspi_opi
board_upload.maximum_size = 4194304
board_upload.maximum_ram_size = 327680
board_upload.flash_size = 4MB

View File

@@ -0,0 +1,6 @@
# This file was automatically generated for projects
# without default 'CMakeLists.txt' file.
FILE(GLOB_RECURSE app_sources ${CMAKE_SOURCE_DIR}/src/*.*)
idf_component_register(SRCS ${app_sources})

View File

@@ -0,0 +1,540 @@
#include "flasher.h"
#include <Arduino.h>
#include <ArduinoJson.h>
#include <MD5Builder.h>
#include "LittleFS.h"
#include "storage.h"
// #include <FS.h>
#include "leds.h"
#include "settings.h"
#include "time.h"
#include "zbs_interface.h"
#define FINGERPRINT_FLASH_SIZE 10240
#ifdef OPENEPAPERLINK_PCB
bool extTagConnected() {
// checks if the TEST (P1.0) pin on the ZBS243 will come up high. If it doesn't, there's probably a tag connected.
pinMode(FLASHER_EXT_TEST, INPUT_PULLDOWN);
vTaskDelay(5 / portTICK_PERIOD_MS);
pinMode(FLASHER_EXT_TEST, INPUT_PULLUP);
vTaskDelay(5 / portTICK_PERIOD_MS);
return !digitalRead(FLASHER_EXT_TEST);
}
#endif
void dump(uint8_t *a, uint16_t l) {
if (a == nullptr) {
Serial.print("Tried to dump the contents of a nullptr, this is probably not what you want.\n");
}
Serial.printf(" ");
#define ROWS 16
for (uint8_t c = 0; c < ROWS; c++) {
Serial.printf(" %02X", c);
}
Serial.printf("\n--------");
for (uint8_t c = 0; c < ROWS; c++) {
Serial.printf("---");
}
for (uint16_t c = 0; c < l; c++) {
if ((c % ROWS) == 0) {
Serial.printf("\n0x%04X | ", c);
}
Serial.printf("%02X ", a[c]);
}
Serial.printf("\n--------");
for (uint8_t c = 0; c < ROWS; c++) {
Serial.printf("---");
}
Serial.printf("\n");
}
int8_t powerPinsExt[] = FLASHER_EXT_POWER;
uint8_t pinsExt[] = {FLASHER_EXT_CLK, FLASHER_EXT_MISO, FLASHER_EXT_MOSI, FLASHER_EXT_RESET, FLASHER_EXT_RXD, FLASHER_EXT_SS, FLASHER_EXT_TEST, FLASHER_EXT_TXD};
flasher::flasher() {
zbs = new ZBS_interface;
Storage.end();
}
flasher::~flasher() {
delete zbs;
Storage.begin();
}
static uint8_t validatePowerPinCount(int8_t *powerPin, uint8_t pinCount) {
return pinCount;
}
#ifndef FLASHER_AP_SPEED
#define FLASHER_AP_SPEED 4000000
#endif
bool flasher::connectTag(uint8_t port) {
bool result;
uint8_t power_pins = 0;
switch (port) {
case 1:
power_pins = validatePowerPinCount(powerPinsExt, sizeof(powerPinsExt));
result = zbs->begin(FLASHER_EXT_SS, FLASHER_EXT_CLK, FLASHER_EXT_MOSI, FLASHER_EXT_MISO, FLASHER_EXT_RESET, (uint8_t *)powerPinsExt, power_pins, FLASHER_AP_SPEED);
break;
default:
Serial.printf("Tried to connect to port %d, but this port isn't available. Some dev borked it up, probably Jelmer.\n", port);
return false;
}
if (!result) Serial.printf("I tried connecting to port %d, but I couldn't establish a link to the tag. That's all I know.\n", port);
return result;
}
void flasher::getFirmwareMD5() {
uint8_t *buffer = (uint8_t *)malloc(FINGERPRINT_FLASH_SIZE);
if (buffer == nullptr) {
Serial.print("couldn't malloc bytes for firmware MD5\n");
return;
}
zbs->select_flash(0);
for (uint16_t c = 0; c < FINGERPRINT_FLASH_SIZE; c++) {
buffer[c] = zbs->read_flash(c);
}
{
MD5Builder md5calc;
md5calc.begin();
md5calc.add(buffer, FINGERPRINT_FLASH_SIZE);
md5calc.calculate();
md5calc.getBytes(md5);
}
for (uint8_t c = 0; c < 16; c++) {
sprintf(md5char + (2 * c), "%02X", md5[c]);
}
Serial.printf("MD5=%s\n", md5char);
free(buffer);
}
bool flasher::getInfoBlockMac() {
if (!zbs->select_flash(1)) return false;
for (uint16_t c = 7; c < 8; c--) {
mac[7 - c] = zbs->read_flash(c + 0x10);
}
Serial.printf("Infopage mac=");
uint16_t macsum = 0;
for (uint8_t c = 0; c < 8; c++) {
macsum += mac[c];
Serial.printf("%02X", mac[c]);
}
Serial.printf("\n");
if (macsum == 0) return false;
if (macsum > 0x5F9) return false;
return true;
}
bool flasher::getInfoBlockMD5() {
if (!zbs->select_flash(1)) return false;
for (uint16_t c = 0; c < 16; c++) {
md5[c] = zbs->read_flash(c + 0x30);
}
uint16_t macsum = 0;
for (uint8_t c = 0; c < 16; c++) {
macsum += md5[c];
sprintf(md5char + (2 * c), "%02X", md5[c]);
}
Serial.printf("Infoblock MD5=%s\n", md5char);
if (macsum == 0) return false; // invalid mac
if (macsum > 0xF00) return false; // *probably* an invalid mac
return true;
}
bool flasher::getInfoBlockType() {
if (!zbs->select_flash(1)) return false;
tagtype = zbs->read_flash(0x19);
return true;
}
bool flasher::findTagByMD5() {
StaticJsonDocument<3000> doc;
DynamicJsonDocument APconfig(600);
fs::File readfile = contentFS->open("/tag_md5_db.json", "r");
DeserializationError err = deserializeJson(doc, readfile);
if (!err) {
for (JsonObject elem : doc.as<JsonArray>()) {
const char *jsonmd5 = elem["MD5"];
if (jsonmd5 != nullptr) {
if (strncmp(md5char, jsonmd5, 32) == 0) {
Serial.print("MD5 Matches > ");
const char *name = elem["name"];
Serial.println(name);
mac_suffix = strtoul(elem["mac_suffix"], 0, 16);
mac_format = elem["mac_format"];
mac_offset = elem["mac_offset"];
tagtype = elem["type"];
readfile.close();
return true;
}
}
}
Serial.print("Failed to find this tag's current firmware MD5 in the json database. If this tag is already OpenEpaperLink, this is to be expected.\n");
} else {
Serial.print("Failed to read json file\n");
}
readfile.close();
return false;
}
bool flasher::findTagByType(uint8_t type) {
StaticJsonDocument<3000> doc;
DynamicJsonDocument APconfig(600);
fs::File readfile = contentFS->open("/tag_md5_db.json", "r");
DeserializationError err = deserializeJson(doc, readfile);
if (!err) {
for (JsonObject elem : doc.as<JsonArray>()) {
if (elem["type"] != nullptr) {
uint8_t jtype = elem["type"];
if (jtype == type) {
Serial.print("Type Matches > ");
const char *name = elem["name"];
Serial.println(name);
const char *jsonmd5 = elem["MD5"];
for (uint8_t c = 0; c < 16; c++) {
uint32_t n = 0;
sscanf(jsonmd5 + (2 * c), "%02X", &n);
md5[c] = (uint8_t)n;
}
for (uint8_t c = 0; c < 16; c++) {
sprintf(md5char + (2 * c), "%02X", md5[c]);
}
mac_suffix = strtoul(elem["mac_suffix"], 0, 16);
mac_format = elem["mac_format"];
mac_offset = elem["mac_offset"];
tagtype = elem["type"];
readfile.close();
return true;
}
}
}
Serial.print("Failed to find this tag's type in the json database.\n");
} else {
Serial.print("Failed to read json file\n");
}
readfile.close();
return false;
}
bool flasher::getFirmwareMac() {
if (!mac_offset) return false;
switch (mac_format) {
case 1:
get_mac_format1();
break;
case 2:
get_mac_format2();
break;
default:
return false;
}
return true;
}
void flasher::getMacFromWiFi() {
mac[0] = 0x00;
mac[1] = 0x00;
esp_read_mac(mac + 2, ESP_MAC_WIFI_SOFTAP);
}
bool flasher::backupFlash() {
getFirmwareMD5();
if (!zbs->select_flash(0)) return false;
md5char[16] = 0x00;
fs::File backup = contentFS->open("/" + (String)md5char + "_backup.bin", "w", true);
for (uint32_t c = 0; c < 65535; c++) {
backup.write(zbs->read_flash(c));
}
backup.close();
return true;
}
// extract original mac from firmware (1.54" and 2.9") and make it 2 bytes longer based on info in settings.h
void flasher::get_mac_format1() {
zbs->select_flash(0);
for (uint8_t c = 0; c < 6; c++) {
mac[c + 2] = zbs->read_flash(mac_offset + c); // 0xFC06
}
mac[0] = (uint8_t)(CUSTOM_MAC_HDR >> 8);
mac[1] = (uint8_t)CUSTOM_MAC_HDR;
mac[6] = (uint8_t)(mac_suffix >> 8);
mac[7] = (uint8_t)(mac_suffix & 0xFF);
uint8_t xorchk = 0;
for (uint8_t c = 2; c < 8; c++) {
xorchk ^= (mac[c] & 0x0F);
xorchk ^= (mac[c] >> 4);
}
mac[7] |= xorchk;
}
// extract original mac from segmented tag
void flasher::get_mac_format2() {
zbs->select_flash(0);
for (uint8_t c = 0; c < 3; c++) {
mac[c] = zbs->read_flash(mac_offset + c); // 0x7802
}
for (uint8_t c = 3; c < 6; c++) {
mac[c] = zbs->read_flash(mac_offset + 2 + c);
}
uint16_t type = mac_suffix;
mac[6] = (uint8_t)(type >> 8);
mac[7] = (uint8_t)(type & 0xFF);
}
// erase flash and program from flash buffer
bool flasher::writeFlash(uint8_t *flashbuffer, uint16_t size) {
if (!zbs->select_flash(0)) return false;
zbs->erase_flash();
if (!zbs->select_flash(0)) return false;
Serial.printf("Starting flash, size=%d\n", size);
for (uint16_t c = 0; c < size; c++) {
if (flashbuffer[c] == 0xFF) goto flashWriteSuccess;
for (uint8_t i = 0; i < MAX_WRITE_ATTEMPTS; i++) {
zbs->write_flash(c, flashbuffer[c]);
if (zbs->read_flash(c) == flashbuffer[c]) {
goto flashWriteSuccess;
}
}
return false;
flashWriteSuccess:
if (c % 256 == 0) {
#ifdef HAS_RGB_LED
shortBlink(CRGB::Yellow);
#else
quickBlink(2);
#endif
Serial.printf("\rNow flashing, %d/%d ", c, size);
vTaskDelay(1 / portTICK_PERIOD_MS);
}
}
return true;
}
bool flasher::writeBlock256(uint16_t offset, uint8_t *flashbuffer) {
for (uint16_t c = 0; c < 256; c++) {
if (flashbuffer[c] == 0xFF) goto flashWriteSuccess;
for (uint8_t i = 0; i < MAX_WRITE_ATTEMPTS; i++) {
zbs->write_flash(offset + c, flashbuffer[c]);
if (zbs->read_flash(offset + c) == flashbuffer[c]) {
goto flashWriteSuccess;
}
}
return false;
flashWriteSuccess:
continue;
}
return true;
}
// get info from infoblock (eeprom flash, kinda)
bool flasher::readInfoBlock() {
if (!zbs->select_flash(1)) return false;
if (infoblock == nullptr) {
infoblock = (uint8_t *)malloc(1024);
if (infoblock == nullptr) return false;
}
for (uint16_t c = 0; c < 1024; c++) {
infoblock[c] = zbs->read_flash(c);
}
return true;
}
// write info to infoblock
bool flasher::writeInfoBlock() {
if (infoblock == nullptr) return false;
if (!zbs->select_flash(1)) return false;
zbs->erase_infoblock();
if (!zbs->select_flash(1)) return false;
// select info page
for (uint16_t c = 0; c < 1024; c++) {
if (infoblock[c] == 0xFF) goto ifBlockWriteSuccess;
for (uint8_t i = 0; i < MAX_WRITE_ATTEMPTS; i++) {
zbs->write_flash(c, infoblock[c]);
if (zbs->read_flash(c) == infoblock[c]) {
goto ifBlockWriteSuccess;
}
}
return false;
ifBlockWriteSuccess:
continue;
}
return true;
}
bool flasher::prepareInfoBlock() {
if (infoblock == nullptr) return false;
for (uint8_t c = 7; c < 8; c--) {
infoblock[0x10 + (7 - c)] = mac[c];
}
infoblock[0x19] = tagtype;
for (uint8_t c = 0; c < 16; c++) {
infoblock[0x30 + c] = md5[c];
}
return true;
}
bool flasher::writeFlashFromPackOffset(fs::File *file, uint16_t length) {
if (!zbs->select_flash(0)) return false;
zbs->erase_flash();
if (!zbs->select_flash(0)) return false;
Serial.printf("Starting flash, size=%d\n", length);
uint8_t *buf = (uint8_t *)malloc(256);
uint16_t offset = 0;
while (length) {
if (length > 256) {
file->read(buf, 256);
length -= 256;
} else {
file->read(buf, length);
length = 0;
}
#ifdef HAS_RGB_LED
shortBlink(CRGB::Yellow);
#else
quickBlink(2);
#endif
Serial.printf("\rFlashing, %d bytes left ", length);
bool res = writeBlock256(offset, buf);
offset += 256;
if (!res) {
Serial.printf("Failed writing block to tag, probably a hardware failure\n");
return false;
}
vTaskDelay(1 / portTICK_PERIOD_MS);
}
Serial.printf("\nFlashing done\n");
return true;
}
bool flasher::writeFlashFromPack(String filename, uint8_t type) {
StaticJsonDocument<512> doc;
DynamicJsonDocument APconfig(512);
fs::File readfile = contentFS->open(filename, "r");
DeserializationError err = deserializeJson(doc, readfile);
if (!err) {
for (JsonObject elem : doc.as<JsonArray>()) {
if (elem["type"] != nullptr) {
uint8_t jtype = elem["type"];
if (jtype == type) {
const char *name = elem["name"];
Serial.print("Flashing from FW pack: ");
Serial.println(name);
uint32_t offset = elem["offset"];
uint16_t length = elem["length"];
readfile.seek(offset);
bool result = writeFlashFromPackOffset(&readfile, length);
readfile.close();
return result;
}
}
}
Serial.print("Failed to find this tag's type in the FW pack database.\n");
} else {
Serial.print("Failed to read json header from FW pack\n");
}
readfile.close();
return false;
}
bool flasher::readBlock(uint16_t offset, uint8_t *data, uint16_t len, bool infopage) {
if (infopage) {
if (!zbs->select_flash(1)) return false;
if (offset > 1024) return false;
} else {
if (!zbs->select_flash(0)) return false;
if (offset > 65535) return false;
}
for (uint32_t c = 0; c < len; c++) {
data[c] = zbs->read_flash(offset + c);
}
return true;
}
bool flasher::writeBlock(uint16_t offset, uint8_t *data, uint16_t len, bool infopage) {
if (infopage) {
if (!zbs->select_flash(1)) return false;
if (offset > 1024) return false;
} else {
if (!zbs->select_flash(0)) return false;
if (offset > 65535) return false;
}
for (uint32_t c = 0; c < len; c++) {
zbs->write_flash(c + offset, data[c]);
}
return true;
}
void flashCountDown(uint8_t c) {
Serial.printf("\r%d ", c);
for (c -= 1; c < 254; c--) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
Serial.printf("\r%d ", c);
}
}
// perform device flash, save mac, everything
bool doTagFlash() {
class flasher *f = new flasher();
if (!f->connectTag(FLASHER_EXT_PORT)) {
Serial.printf("Sorry, failed to connect to this tag...\n");
return false;
}
f->getFirmwareMD5();
if (f->findTagByMD5()) {
// this tag currently contains original firmware, found its fingerprint
Serial.printf("Found original firmware tag, recognized its fingerprint (%s)\n", f->md5char);
f->readInfoBlock();
f->getFirmwareMac();
f->prepareInfoBlock();
f->writeInfoBlock();
f->writeFlashFromPack("/Tag_FW_Pack.bin", f->tagtype);
f->zbs->reset();
} else if (f->getInfoBlockMD5()) {
// did find an infoblock MD5 that looks valid
if (f->findTagByMD5()) {
// did find the md5 in the database
Serial.printf("Found an already-flashed tag, recognized its fingerprint (%s)\n", f->md5char);
f->getInfoBlockMac();
f->getInfoBlockType();
f->readInfoBlock();
f->writeFlashFromPack("/Tag_FW_Pack.bin", f->tagtype);
f->zbs->reset();
} else {
// couldn't find the md5 from the infoblock
Serial.printf("Found an already-flashed tag, but we couldn't find its fingerprint (%s) in the database\n", f->md5char);
return false;
}
} else {
// We couldn't recognize the tag from it's fingerprint...
Serial.printf("Found a tag but didn't recognize its fingerprint\n", f->md5char);
f->backupFlash();
Serial.printf("Saved this MD5 binary to filesystem\n");
}
delete f;
return false;
}

View File

@@ -0,0 +1,331 @@
#include <Arduino.h>
#ifdef HAS_RGB_LED
#define FASTLED_INTERNAL
#include <FastLED.h>
#endif
#include "leds.h"
#include "settings.h"
QueueHandle_t ledQueue;
int maxledbrightness = 255;
#ifdef HAS_RGB_LED
QueueHandle_t rgbLedQueue;
struct ledInstructionRGB {
CRGB ledColor;
uint16_t fadeTime;
uint16_t length;
bool reQueue = false;
};
CRGB leds[1];
volatile bool rgbQueueFlush = false;
#endif
struct ledInstruction {
uint16_t value;
uint16_t fadeTime;
uint16_t length;
bool reQueue = false;
};
#ifdef HAS_RGB_LED
void addToRGBQueue(struct ledInstructionRGB* rgb, bool requeue) {
rgb->reQueue = requeue;
if (!rgbLedQueue) {
delete rgb;
return;
}
BaseType_t queuestatus = xQueueSend(rgbLedQueue, &rgb, 0);
if (queuestatus == pdFALSE) {
delete rgb;
}
}
void addFadeColor(CRGB cname) {
struct ledInstructionRGB* rgb = new struct ledInstructionRGB;
rgb->ledColor = cname;
rgb->fadeTime = 750;
rgb->length = 0;
addToRGBQueue(rgb, false);
}
void shortBlink(CRGB cname) {
struct ledInstructionRGB* rgb = new struct ledInstructionRGB;
rgb->ledColor = CRGB::Black;
rgb->fadeTime = 0;
rgb->length = 3;
addToRGBQueue(rgb, false);
rgb = new struct ledInstructionRGB;
rgb->ledColor = cname;
rgb->ledColor.maximizeBrightness(0x80);
rgb->fadeTime = 0;
rgb->length = 10;
addToRGBQueue(rgb, false);
rgb = new struct ledInstructionRGB;
rgb->ledColor = CRGB::Black;
rgb->fadeTime = 0;
rgb->length = 3;
addToRGBQueue(rgb, false);
}
void flushRGBQueue() {
rgbQueueFlush = true;
}
void rgbIdle() {
flushRGBQueue();
}
void showColorPattern(CRGB colorone, CRGB colortwo, CRGB colorthree) {
struct ledInstructionRGB* rgb = new struct ledInstructionRGB;
rgb->ledColor = CRGB::Black;
rgb->fadeTime = 0;
rgb->length = 600;
addToRGBQueue(rgb, true);
rgb = new struct ledInstructionRGB;
rgb->ledColor = colorone;
rgb->fadeTime = 0;
rgb->length = 120;
addToRGBQueue(rgb, true);
rgb = new struct ledInstructionRGB;
rgb->ledColor = CRGB::Black;
rgb->fadeTime = 0;
rgb->length = 200;
addToRGBQueue(rgb, true);
rgb = new struct ledInstructionRGB;
rgb->ledColor = colortwo;
rgb->fadeTime = 0;
rgb->length = 120;
addToRGBQueue(rgb, true);
rgb = new struct ledInstructionRGB;
rgb->ledColor = CRGB::Black;
rgb->fadeTime = 0;
rgb->length = 200;
addToRGBQueue(rgb, true);
rgb = new struct ledInstructionRGB;
rgb->ledColor = colorthree;
rgb->fadeTime = 0;
rgb->length = 120;
addToRGBQueue(rgb, true);
}
void showRGB() {
FastLED.show();
}
volatile CRGB rgbIdleColor = CRGB::Green;
volatile uint16_t rgbIdlePeriod = 800;
void rgbIdleStep() {
static bool dirUp = true;
static uint16_t step = 0;
if (dirUp) {
// up
step++;
if (step == rgbIdlePeriod) {
dirUp = false;
}
} else {
// down
step--;
if (step == 0) {
dirUp = true;
}
}
CRGB newvalue = blend(CRGB::Black, (const CRGB&)rgbIdleColor, gamma8[map(step, 0, rgbIdlePeriod, 0, 255)]);
if (newvalue != leds[0]) {
leds[0] = newvalue;
showRGB();
}
}
#endif
void setBrightness(int brightness) {
maxledbrightness = brightness;
#ifdef HAS_RGB_LED
FastLED.setBrightness(maxledbrightness);
#endif
}
void addToMonoQueue(struct ledInstruction* mono) {
BaseType_t queuestatus = xQueueSend(ledQueue, &mono, 0);
if (queuestatus == pdFALSE) {
delete mono;
}
}
void addFadeMono(uint8_t value) {
struct ledInstruction* mono = new struct ledInstruction;
mono->value = value;
mono->fadeTime = 750;
mono->length = 0;
addToMonoQueue(mono);
}
void showMono(uint8_t brightness) {
#ifdef CONFIG_IDF_TARGET_ESP32S2
ledcWrite(7, gamma8[brightness]);
#else
ledcWrite(7, 255 - gamma8[brightness]);
#endif
}
void quickBlink(uint8_t repeat) {
for (int i = 0; i < repeat; i++) {
struct ledInstruction* mono = new struct ledInstruction;
mono->value = maxledbrightness;
mono->fadeTime = 120 / repeat;
mono->length = 0;
addToMonoQueue(mono);
mono = new struct ledInstruction;
mono->value = 0;
mono->fadeTime = 120 / repeat;
mono->length = 0;
addToMonoQueue(mono);
}
}
volatile uint16_t monoIdlePeriod = 900;
uint8_t monoValue = 0;
void monoIdleStep() {
static bool dirUp = true;
static uint16_t step = 0;
if (dirUp) {
// up
step++;
if (step == monoIdlePeriod) {
dirUp = false;
}
} else {
// down
step--;
if (step == 0) {
dirUp = true;
}
}
uint8_t newvalue = map(step, 0, monoIdlePeriod, 0, maxledbrightness);
if (newvalue != monoValue) {
monoValue = newvalue;
showMono(newvalue);
}
}
void ledTask(void* parameter) {
#ifdef HAS_RGB_LED
FastLED.addLeds<WS2812B, FLASHER_RGB_LED, GRB>(leds, 1); // GRB ordering is typical
leds[0] = CRGB::Blue;
showRGB();
rgbLedQueue = xQueueCreate(30, sizeof(struct ledInstructionRGB*));
struct ledInstructionRGB* rgb = nullptr;
// open with a nice RGB crossfade
addFadeColor(CRGB::Red);
addFadeColor(CRGB::Green);
addFadeColor(CRGB::Blue);
addFadeColor(CRGB::Red);
addFadeColor(CRGB::Green);
addFadeColor(CRGB::Blue);
CRGB oldColor = CRGB::Black;
uint16_t rgbInstructionFadeTime = 0;
#endif
ledQueue = xQueueCreate(30, sizeof(struct ledInstruction*));
ledcSetup(7, 5000, 8);
if (FLASHER_LED != -1) {
digitalWrite(FLASHER_LED, HIGH);
pinMode(FLASHER_LED, OUTPUT);
ledcAttachPin(FLASHER_LED, 7);
}
struct ledInstruction* monoled = nullptr;
addFadeMono(0);
addFadeMono(maxledbrightness);
addFadeMono(0);
uint8_t oldBrightness = 0;
uint16_t monoInstructionFadeTime = 0;
while (1) {
#ifdef HAS_RGB_LED
// handle RGB led instructions
if (rgb == nullptr) {
// fetch a led instruction
BaseType_t q = xQueueReceive(rgbLedQueue, &rgb, 1);
if (q == pdTRUE) {
if (rgb->reQueue && !rgbQueueFlush) {
// requeue this instruction at the end of the queue, caveman style.
struct ledInstructionRGB* requeue = new ledInstructionRGB;
requeue->fadeTime = rgb->fadeTime;
requeue->ledColor = rgb->ledColor;
requeue->length = rgb->length;
addToRGBQueue(requeue, true);
}
if (rgbQueueFlush) {
delete rgb;
rgb = nullptr;
} else {
rgbInstructionFadeTime = rgb->fadeTime;
if (rgb->fadeTime <= 1) {
leds[0] = rgb->ledColor;
showRGB();
}
}
} else {
rgbQueueFlush = false;
// no commands, run idle led task
rgbIdleStep();
}
} else {
// process instruction
if (rgb->fadeTime) {
rgb->fadeTime--;
leds[0] = blend(rgb->ledColor, oldColor, map(rgb->fadeTime, 0, rgbInstructionFadeTime, 0, 255));
showRGB();
} else if (rgb->length) {
rgb->length--;
} else {
oldColor = rgb->ledColor;
delete rgb;
rgb = nullptr;
}
}
#endif
// handle flasher LED (single color)
if (monoled == nullptr) {
BaseType_t q = xQueueReceive(ledQueue, &monoled, 1);
if (q == pdTRUE) {
monoInstructionFadeTime = monoled->fadeTime;
if (monoled->fadeTime <= 1) {
showMono(monoled->value);
}
} else {
// monoIdleStep();
}
} else {
if (monoled->fadeTime) {
monoled->fadeTime--;
showMono(map(monoled->fadeTime, 0, monoInstructionFadeTime, monoled->value, oldBrightness));
} else if (monoled->length) {
monoled->length--;
} else {
oldBrightness = monoled->value;
delete monoled;
monoled = nullptr;
}
}
vTaskDelay(1 / portTICK_PERIOD_MS);
}
}

View File

@@ -0,0 +1,51 @@
#include <Arduino.h>
#include <WiFi.h>
#include <time.h>
#include "flasher.h"
#include "leds.h"
#include "settings.h"
#include "udp.h"
#include "usbflasher.h"
#include "powermgt.h"
void setup() {
Serial.begin(115200);
Serial.print(">\n");
xTaskCreate(ledTask, "ledhandler", 2000, NULL, 2, NULL);
vTaskDelay(10 / portTICK_PERIOD_MS);
// this allows us to view the booting process. After the device showing up, you have 3 seconds to open a terminal on the COM port
vTaskDelay(3000 / portTICK_PERIOD_MS);
// Specifically for the Mini-version (using an ESP32-S2), use another serial port for debug output. Makes it possible to see core dumps
Serial0.begin(115200, SERIAL_8N1, 2, 3);
Serial0.printf("Started debug output...\n");
Serial0.setDebugOutput(true);
// pinTest();
if (!psramInit()) {
Serial.printf("This build of the AP expects PSRAM, but we couldn't find/init any. Something is terribly wrong here! System halted.");
while (1) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
};
heap_caps_malloc_extmem_enable(64);
int8_t powerPins2[] = FLASHER_EXT_POWER;
powerControl(0, (uint8_t*)powerPins2, 4);
// We'll need to start the 'usbflasher' task for boards with a second (USB) port. This can be used as a 'flasher' interface, using a python script on the host
pinMode(FLASHER_EXT_RESET, OUTPUT);
digitalWrite(FLASHER_EXT_RESET, HIGH);
// pinMode(FLASHER_EXT_TEST, OUTPUT);
// digitalWrite(FLASHER_EXT_TEST, HIGH);
xTaskCreate(usbFlasherTask, "usbflasher", 10000, NULL, configMAX_PRIORITIES - 10, NULL);
}
void loop() {
vTaskDelay(10000 / portTICK_PERIOD_MS);
}

View File

@@ -0,0 +1,31 @@
#include "powermgt.h"
#include <Arduino.h>
#include "settings.h"
#ifdef OPENEPAPERLINK_PCB
#include "soc/rtc_cntl_reg.h"
#include "soc/soc.h"
#endif
void simpleAPPower(uint8_t* pin, uint8_t pincount, bool state) {
for (uint8_t c = 0; c < pincount; c++) {
pinMode(pin[c], INPUT);
}
for (uint8_t c = 0; c < pincount; c++) {
digitalWrite(pin[c], state);
}
for (uint8_t c = 0; c < pincount; c++) {
pinMode(pin[c], OUTPUT);
}
}
void powerControl(bool powerState, uint8_t* pin, uint8_t pincount) {
if (pincount == 0) return;
if (pin == nullptr) return;
pincount = 4;
simpleAPPower(pin, pincount, powerState);
}

View File

@@ -0,0 +1,216 @@
#include "storage.h"
#ifdef HAS_SDCARD
#include "FS.h"
#include "SD.h"
#include "SPI.h"
#endif
#include "LittleFS.h"
DynStorage::DynStorage() : isInited(0) {}
static void initLittleFS() {
LittleFS.begin();
contentFS = &LittleFS;
}
#ifdef HAS_SDCARD
static SPIClass* spi;
static void initSDCard() {
uint8_t spi_bus = VSPI;
// SD.begin and spi.begin are allocating memory so we dont want to do that
if(!spi) {
spi = new SPIClass(spi_bus);
spi->begin(SD_CARD_CLK, SD_CARD_MISO, SD_CARD_MOSI, SD_CARD_SS);
bool res = SD.begin(SD_CARD_SS, *spi, 40000000);
if (!res) {
Serial.println("Card Mount Failed");
return;
}
}
uint8_t cardType = SD.cardType();
if (cardType == CARD_NONE) {
Serial.println("No SD card attached");
return;
}
contentFS = &SD;
}
#endif
size_t DynStorage::freeSpace(){
this->begin();
#ifdef HAS_SDCARD
return SD.totalBytes() - SD.usedBytes();
#endif
return LittleFS.totalBytes() - LittleFS.usedBytes();
}
void copyFile(File in, File out) {
Serial.print("Copying ");
Serial.print(in.path());
Serial.print(" to ");
Serial.println(out.path());
size_t n;
uint8_t buf[64];
while ((n = in.read(buf, sizeof(buf))) > 0) {
out.write(buf, n);
}
}
#ifdef HAS_SDCARD
void copyBetweenFS(FS& sourceFS, const char* source_path, FS& targetFS) {
File root = sourceFS.open(source_path);
char next_path[128];
if (root.isDirectory()) {
if (!contentFS->exists(root.path())) {
if (!contentFS->mkdir(root.path())) {
Serial.print("Failed to create directory ");
Serial.println(root.path());
return;
}
}
File file = root.openNextFile();
while (file) {
if (file.isDirectory()) {
sprintf(next_path, "%s/%s\0", root.path(), file.path());
copyBetweenFS(sourceFS, file.path(), targetFS);
} else {
File target = contentFS->open(file.path(), "w");
if (target) {
copyFile(file, target);
target.close();
file.close();
} else {
Serial.print("Couldn't create high target file");
Serial.println(file.path());
return;
}
}
file = root.openNextFile();
}
} else {
File target = contentFS->open(root.path(), "w");
if (target) {
copyFile(root, target);
} else {
Serial.print("Couldn't create target file ");
Serial.println(root.path());
return;
}
}
}
void copyIfNeeded(const char* path) {
if (!contentFS->exists(path) && LittleFS.exists(path)) {
Serial.printf("SDCard does not contain %s, littleFS does, copying\n", path);
copyBetweenFS(LittleFS, path, *contentFS);
}
}
#endif
void DynStorage::begin() {
initLittleFS();
#ifdef HAS_SDCARD
initSDCard();
copyIfNeeded("/index.html");
copyIfNeeded("/fonts");
copyIfNeeded("/www");
copyIfNeeded("/tagtypes");
copyIfNeeded("/AP_FW_Pack.bin");
copyIfNeeded("/tag_md5_db.json");
copyIfNeeded("/update_actions.json");
copyIfNeeded("/content_template.json");
#endif
if (!contentFS->exists("/current")) {
contentFS->mkdir("/current");
}
if (!contentFS->exists("/temp")) {
contentFS->mkdir("/temp");
}
}
void DynStorage::end() {
#ifdef HAS_SDCARD
initLittleFS();
if (SD_CARD_CLK == FLASHER_AP_CLK ||
SD_CARD_MISO == FLASHER_AP_MISO ||
SD_CARD_MOSI == FLASHER_AP_MOSI) {
Serial.println("Tearing down SD card connection");
copyBetweenFS(*contentFS, "/tag_md5_db.json", LittleFS);
copyBetweenFS(*contentFS, "/AP_FW_Pack.bin", LittleFS);
if (contentFS->exists("/AP_force_flash.bin")) {
copyBetweenFS(*contentFS, "/AP_force_flash.bin", LittleFS);
contentFS->remove("/AP_force_flash.bin");
}
Serial.println("Swapping to LittleFS");
contentFS = &LittleFS;
}
#endif
}
void listDir(fs::FS& fs, const char* dirname, uint8_t levels) {
Storage.begin();
Serial.printf(" \n ");
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if (!root) {
Serial.println("Failed to open directory");
return;
}
if (!root.isDirectory()) {
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while (file) {
if (!strcmp("System Volume Information", file.name())) {
file = root.openNextFile();
continue;
}
if (file.isDirectory()) {
Serial.print(" DIR : ");
Serial.println(file.name());
if (levels) {
listDir(fs, file.path(), levels - 1);
}
Serial.println();
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void DynStorage::listFiles() {
listDir(LittleFS, "/", 1);
#ifdef HAS_SDCARD
listDir(*contentFS, "/", 1);
#endif
}
fs::FS* contentFS;
DynStorage Storage;

View File

@@ -0,0 +1,393 @@
/*
Copyright (c) 2021 Aaron Christophel ATCnetz.de
SPDX-License-Identifier: GPL-3.0-or-later
*/
#include "swd.h"
#include "Arduino.h"
// Many thanks to scanlime for the work on the ESP8266 SWD Library, parts of this code have inspiration and help from it
// https://github.com/scanlime/esp8266-arm-swd
#define DP_IDCODE 0x00
swd::swd(uint8_t swdio, uint8_t swdclk) {
this->swdio_pin = swdio;
this->swdclk_pin = swdclk;
this->swd_Begin();
}
void swd::swd_Begin() {
pinMode(this->swdclk_pin, OUTPUT);
pinMode(this->swdio_pin, INPUT_PULLUP);
}
uint32_t swd::swd_Init() { // Returns the ID
swd_Write(0xffffffff, 32);
swd_Write(0xffffffff, 32);
swd_Write(0xe79e, 16);
swd_Write(0xffffffff, 32);
swd_Write(0xffffffff, 32);
swd_Write(0, 32);
swd_Write(0, 32);
DP_Read(DP_IDCODE, this->idCode);
return this->idCode;
}
bool swd::AP_Write(unsigned addr, uint32_t data) {
uint8_t retry = 15;
while (retry--) {
bool state = swd_Transfer(addr, 1, 0, data);
if (state)
return true;
}
return false;
}
bool swd::AP_Read(unsigned addr, uint32_t &data) {
uint8_t retry = 15;
while (retry--) {
bool state = swd_Transfer(addr, 1, 1, data);
if (state)
return true;
}
return false;
}
bool swd::DP_Write(unsigned addr, uint32_t data) {
uint8_t retry = 15;
while (retry--) {
bool state = swd_Transfer(addr, 0, 0, data);
if (state)
return true;
}
return false;
}
bool swd::DP_Read(unsigned addr, uint32_t &data) {
uint8_t retry = 15;
while (retry--) {
bool state = swd_Transfer(addr, 0, 1, data);
if (state)
return true;
}
return false;
}
bool swd::swd_Transfer(unsigned port_address, bool APorDP, bool RorW, uint32_t &data) {
bool parity = APorDP ^ RorW ^ ((port_address >> 2) & 1) ^ ((port_address >> 3) & 1);
uint8_t filled_address = (1 << 0) | (APorDP << 1) | (RorW << 2) | ((port_address & 0xC) << 1) | (parity << 5) | (1 << 7);
swd_Write(filled_address, 8);
if (swd_Read(3) == 1) {
if (RorW) { // Reading 32 bits from SWD
data = swd_Read(32);
if (swd_Read(1) == calculate_Parity(data)) {
swd_Write(0, 1);
return true;
}
} else { // Writing 32bits to SWD
swd_Write(data, 32);
swd_Write(calculate_Parity(data), 1);
swd_Write(0, 1);
return true;
}
}
swd_Write(0, 32);
return false;
}
bool swd::calculate_Parity(uint32_t in_data) {
in_data = (in_data & 0xFFFF) ^ (in_data >> 16);
in_data = (in_data & 0xFF) ^ (in_data >> 8);
in_data = (in_data & 0xF) ^ (in_data >> 4);
in_data = (in_data & 0x3) ^ (in_data >> 2);
in_data = (in_data & 0x1) ^ (in_data >> 1);
return in_data;
}
void swd::swd_Write(uint32_t in_data, uint8_t bits) {
if (cur_swd_direction == 0)
swd_Direction(1);
while (bits--) {
digitalWrite(this->swdio_pin, in_data & 1);
digitalWrite(this->swdclk_pin, LOW);
delayMicroseconds(2);
in_data >>= 1;
digitalWrite(this->swdclk_pin, HIGH);
delayMicroseconds(2);
}
}
uint32_t swd::swd_Read(uint8_t bits) {
uint32_t out_data = 0;
uint32_t input_bit = 1;
if (cur_swd_direction == 1)
swd_Direction(0);
while (bits--) {
if (digitalRead(this->swdio_pin)) {
out_data |= input_bit;
}
digitalWrite(this->swdclk_pin, LOW);
delayMicroseconds(2);
input_bit <<= 1;
digitalWrite(this->swdclk_pin, HIGH);
delayMicroseconds(2);
}
return out_data;
}
void swd::swd_Direction(bool WorR) { // 1 = Write 0 = Read
digitalWrite(this->swdio_pin, HIGH);
pinMode(this->swdio_pin, INPUT_PULLUP);
digitalWrite(this->swdclk_pin, LOW);
delayMicroseconds(2);
digitalWrite(this->swdclk_pin, HIGH);
delayMicroseconds(2);
if (WorR)
pinMode(this->swdio_pin, OUTPUT);
cur_swd_direction = WorR;
}
#define PORT_AP true
#define PORT_DP false
#define AP_NRF_RESET 0x00
#define AP_NRF_ERASEALL 0x04
#define AP_NRF_ERASEALLSTATUS 0x08
#define AP_NRF_ERASEALL 0x04
#define AP_NRF_APPROTECTSTATUS 0x0c
#define AP_NRF_IDR 0xfc
#define AP_CSW 0x00
#define AP_TAR 0x04
#define AP_DRW 0x0c
#define AP_BD0 0x10
#define AP_BD1 0x14
#define AP_BD2 0x18
#define AP_BD3 0x1c
#define AP_DBGDRAR 0xf8
#define AP_IDR 0xfc
#define DP_ABORT 0x00
#define DP_CTRLSTAT 0x04
#define DP_SELECT 0x08
#define DP_RDBUFF 0x0c
nrfswd::nrfswd(uint8_t swdio, uint8_t swdclk) : swd(swdio, swdclk) {
}
bool nrfswd::init() {
uint32_t temp = swd_Init();
nrf_abort_all();
if (temp == 0x2ba01477) { // if core id is readable the connection is working
if (showDebug) Serial.printf("Connected to nRF\n");
isConnected = true;
if (nrf_read_lock_state()) { // nRF is unlocked so we can talk to the debugging interface
if (showDebug) Serial.printf("nRF is unlocked!\n");
isLocked = false;
nrf_halt();
nrf_read_ufcr();
return true;
} else {
if (showDebug) Serial.printf("nRF is locked ;_;\n");
isLocked = true;
}
} else {
isConnected = false;
isLocked = true;
}
return false;
}
uint32_t nrfswd::nrf_read_port(bool APorDP, uint8_t address) {
uint32_t temp = 0;
if (APorDP == PORT_AP)
AP_Read(address, temp);
else
DP_Read(address, temp);
DP_Read(DP_RDBUFF, temp);
DP_Read(DP_RDBUFF, temp);
Serial.printf("%s Read reg: 0x%02x : 0x%08x\r\n", APorDP ? "AP" : "DP", address, temp);
return temp;
}
void nrfswd::nrf_write_port(bool APorDP, uint8_t address, uint32_t value) {
uint32_t temp = 0;
if (APorDP == PORT_AP)
AP_Write(address, value);
else
DP_Write(address, value);
DP_Read(DP_RDBUFF, temp);
DP_Read(DP_RDBUFF, temp);
Serial.printf("%s Write reg: 0x%02x : 0x%08x\r\n", APorDP ? "AP" : "DP", address, value);
}
void nrfswd::nrf_abort_all() {
nrf_write_port(0, DP_ABORT, 0x1e);
nrf_write_port(0, DP_CTRLSTAT, 0x50000000);
}
void nrfswd::nrf_halt() {
AP_Write(AP_CSW, 0xa2000002);
AP_Write(AP_TAR, 0xe000edf0);
uint32_t retry = 500;
while (retry--) {
AP_Write(AP_DRW, 0xA05F0003);
}
}
void nrfswd::nrf_port_selection(bool new_port) {
DP_Write(DP_SELECT, new_port ? 0x01000000 : 0x00); // Select AP
}
bool nrfswd::nrf_read_lock_state() {
uint32_t temp;
nrf_port_selection(1);
temp = nrf_read_port(1, AP_NRF_APPROTECTSTATUS);
nrf_port_selection(0);
return temp & 1;
}
void nrfswd::nrf_read_ufcr() {
nrf_info.codepage_size = read_register(0x10000010);
nrf_info.codesize = read_register(0x10000014);
nrf_info.flash_size = nrf_info.codepage_size * nrf_info.codesize;
nrf_info.config_id = read_register(0x1000005c);
nrf_info.device_id0 = read_register(0x10000060);
nrf_info.device_id1 = read_register(0x10000064);
nrf_info.info_part = read_register(0x10000100);
nrf_info.info_variant = read_register(0x10000104);
nrf_info.info_package = read_register(0x10000108);
nrf_info.sd_info_area = read_register(0x0000300C) & 0xffff;
nrf_info.ucir_lock = read_register(0x10001208);
if (showDebug) {
Serial.printf("Device: nRF%8X\n", nrf_info.info_part);
Serial.printf("Flash size: %i\r\n", nrf_info.flash_size);
}
}
uint32_t nrfswd::read_register(uint32_t address) {
uint32_t temp = 0;
bool state1 = AP_Write(AP_TAR, address);
bool state2 = AP_Read(AP_DRW, temp);
bool state3 = DP_Read(DP_RDBUFF, temp);
bool state4 = DP_Read(DP_RDBUFF, temp);
if (showDebug)
Serial.printf("%i%i%i%i Read Register: 0x%08x : 0x%08x\r\n", state1, state2, state3, state4, address, temp);
return temp;
}
void nrfswd::write_register(uint32_t address, uint32_t value) {
uint32_t temp = 0;
bool state1 = AP_Write(AP_TAR, address);
bool state2 = AP_Write(AP_DRW, value);
bool state3 = DP_Read(DP_RDBUFF, temp);
if (showDebug)
Serial.printf("%i%i%i Write Register: 0x%08x : 0x%08x\r\n", state1, state2, state3, address, value);
}
uint8_t nrfswd::erase_all_flash() {
write_register(0x4001e504, 2);
long timeout = millis();
while (read_register(0x4001e400) != 1) {
if (millis() - timeout > 100) return 1;
}
write_register(0x4001e50c, 1);
timeout = millis();
while (read_register(0x4001e400) != 1) {
if (millis() - timeout > 1000) return 1;
}
write_register(0x4001e504, 0);
timeout = millis();
while (read_register(0x4001e400) != 1) {
if (millis() - timeout > 100) return 1;
}
return 0;
}
uint8_t nrfswd::erase_uicr() {
write_register(0x4001e504, 2);
long timeout = millis();
while (read_register(0x4001e400) != 1) {
if (millis() - timeout > 100) return 1;
}
write_register(0x4001e514, 1);
timeout = millis();
while (read_register(0x4001e400) != 1) {
if (millis() - timeout > 1000) return 1;
}
write_register(0x4001e504, 0);
timeout = millis();
while (read_register(0x4001e400) != 1) {
if (millis() - timeout > 100) return 1;
}
return 0;
}
uint8_t nrfswd::erase_page(uint32_t page) {
write_register(0x4001e504, 2);
long timeout = millis();
while (read_register(0x4001e400) != 1) {
if (millis() - timeout > 100) return 1;
}
write_register(0x4001e508, page);
timeout = millis();
while (read_register(0x4001e400) != 1) {
if (millis() - timeout > 500) return 1;
}
write_register(0x4001e504, 0);
timeout = millis();
while (read_register(0x4001e400) != 1) {
if (millis() - timeout > 100) return 1;
}
return 0;
}
void nrfswd::nrf_soft_reset(){
nrf_port_selection(1);
nrf_write_port(1, AP_NRF_RESET, 1);
delay(100);
nrf_write_port(1, AP_NRF_RESET, 0);
nrf_port_selection(0);
}
uint8_t nrfswd::nrf_write_bank(uint32_t address, uint32_t buffer[], int size) {
if (!isConnected)
return 1; // not connected to an nRF
if (size > 4096)
return 2; // buffer bigger then a bank
uint32_t temp;
write_register(0x4001e504, 1); // NVIC Enable writing
long timeout = millis();
while (read_register(0x4001e400) != 1) {
if (millis() - timeout > 100) return 3;
}
AP_Write(AP_CSW, 0xa2000012);
AP_Write(AP_TAR, address);
for (int posi = 0; posi < size; posi += 4) {
long end_micros = micros() + 400; // wait till writing of nRF memory is done without asking for ready state
AP_Write(AP_DRW, buffer[posi / 4]);
while (micros() < end_micros) {
};
}
AP_Write(AP_CSW, 0xa2000002);
DP_Read(DP_RDBUFF, temp);
DP_Read(DP_RDBUFF, temp);
write_register(0x4001e504, 0); // NVIC Diasble writing
timeout = millis();
while (read_register(0x4001e400) != 1) {
if (millis() - timeout > 100) return 3;
}
return 0;
}
uint8_t nrfswd::nrf_read_bank(uint32_t address, uint32_t buffer[], int size) {
if (!isConnected)
return 1; // not connected to an nRF
uint32_t temp;
AP_Write(AP_CSW, 0xa2000012);
AP_Write(AP_TAR, address);
AP_Read(AP_DRW, temp);
uint32_t curr_word = 0;
for (int posi = 0; posi < size; posi += 4) {
AP_Read(AP_DRW, curr_word);
buffer[posi / 4] = curr_word;
}
AP_Write(AP_CSW, 0xa2000002);
DP_Read(DP_RDBUFF, temp);
DP_Read(DP_RDBUFF, temp);
return 0;
}

View File

@@ -0,0 +1,582 @@
#include <Arduino.h>
#include "USB.h"
#include "flasher.h"
#include "leds.h"
#include "powermgt.h"
#include "settings.h"
#include "swd.h"
#include "zbs_interface.h"
USBCDC USBSerial;
QueueHandle_t flasherCmdQueue;
uint32_t usbConnectedStartTime = 0;
bool serialPassthroughState = false;
#define FLASHER_WAIT_A 0
#define FLASHER_WAIT_T 1
#define FLASHER_WAIT_CMD 2
#define FLASHER_WAIT_LEN 3
#define FLASHER_WAIT_DATA 4
#define FLASHER_WAIT_CRCH 5
#define FLASHER_WAIT_CRCL 6
struct flasherCommand {
uint8_t command = 0;
uint32_t len = 0;
uint8_t* data = nullptr;
};
int8_t powerPins2[] = FLASHER_EXT_POWER;
bool autoFlash(flasher* f) {
f->getFirmwareMD5();
if (f->findTagByMD5()) {
// this tag currently contains original firmware, found its fingerprint
USBSerial.printf("Found original firmware tag, recognized its fingerprint (%s)\n", f->md5char);
f->readInfoBlock();
f->getFirmwareMac();
f->prepareInfoBlock();
f->writeInfoBlock();
USBSerial.printf("Attempting to perform a flash...\n");
if (f->writeFlashFromPack("/Tag_FW_Pack.bin", f->tagtype)) {
USBSerial.printf("Successfully flashed the tag!\n");
return true;
} else {
USBSerial.printf("Couldn't flash the tag, for some reason...\n");
}
} else if (f->getInfoBlockMD5()) {
// did find an infoblock MD5 that looks valid
if (f->findTagByMD5()) {
// did find the md5 in the database
USBSerial.printf("Found an already-flashed tag, recognized its fingerprint (%s)\n", f->md5char);
f->getInfoBlockMac();
f->getInfoBlockType();
f->readInfoBlock();
USBSerial.printf("Attempting to perform a flash...\n");
if (f->writeFlashFromPack("/Tag_FW_Pack.bin", f->tagtype)) {
USBSerial.printf("Successfully flashed the tag!\n");
return true;
} else {
USBSerial.printf("Couldn't flash the tag, for some reason...\n");
}
} else {
// couldn't find the md5 from the infoblock
USBSerial.printf("Found an already-flashed tag, but we couldn't find its fingerprint (%s) in the database\n", f->md5char);
return false;
}
} else {
// We couldn't recognize the tag from it's fingerprint...
USBSerial.printf("Found a tag but didn't recognize its fingerprint\n", f->md5char);
f->backupFlash();
USBSerial.printf("Saved this MD5 binary to filesystem\n");
}
return false;
}
void sendFlasherAnswer(uint8_t answer_cmd, uint8_t* ans_buff, uint32_t len) {
uint8_t* answer_buffer = (uint8_t*)calloc(3 + 2 + 2 + len + 2 + 13, 1);
if (answer_buffer == nullptr) return;
uint32_t CRC_value = 0xAB34;
answer_buffer[0] = 'A';
answer_buffer[1] = 'T';
answer_buffer[2] = answer_cmd;
CRC_value += answer_cmd;
for (uint8_t c = 0; c < 4; c++) {
answer_buffer[3 + c] = (uint8_t)(len >> (24 - (c * 8)));
CRC_value += answer_buffer[3 + c];
}
for (int i = 0; i < len; i++) {
answer_buffer[7 + i] = ans_buff[i];
CRC_value += ans_buff[i];
}
answer_buffer[3 + 2 + 2 + len] = CRC_value >> 8;
answer_buffer[3 + 2 + 2 + len + 1] = CRC_value;
USBSerial.write(answer_buffer, 3 + 2 + 2 + len + 2);
// for(uint16_t c = 0; c< 3+2+2+len+2; c++){
//}
free(answer_buffer);
}
void flasherUartHandler(uint8_t* data, uint8_t len) {
static struct flasherCommand* cmd;
static uint8_t flasherSerialState = FLASHER_WAIT_A;
static uint32_t flasherCmdDataIndex = 0;
static uint16_t flasherCRC = 0xAB34;
static uint32_t flasherLastCmd = 0;
static uint8_t curLenIndex = 0;
if ((flasherSerialState != FLASHER_WAIT_A) && (millis() - flasherLastCmd >= 225)) {
flasherSerialState = FLASHER_WAIT_A;
// we should probably do something with stale commands containing data (data leak!)
}
while (len--) {
uint8_t usbbyte = *(data++);
switch (flasherSerialState) {
case FLASHER_WAIT_A:
if (usbbyte == 'A') {
flasherSerialState = FLASHER_WAIT_T;
flasherLastCmd = millis();
} else {
// enterConsoleMode();
}
break;
case FLASHER_WAIT_T:
if (usbbyte == 'T') {
flasherSerialState = FLASHER_WAIT_CMD;
cmd = new flasherCommand;
flasherCRC = 0xAB34;
flasherCmdDataIndex = 0;
} else {
flasherSerialState = FLASHER_WAIT_A;
}
break;
case FLASHER_WAIT_CMD:
cmd->command = usbbyte;
flasherCRC += usbbyte;
flasherSerialState = FLASHER_WAIT_LEN;
curLenIndex = 0;
break;
case FLASHER_WAIT_LEN:
flasherCRC += usbbyte;
cmd->len |= ((uint32_t)usbbyte) << (24 - (8 * curLenIndex));
curLenIndex++;
if (curLenIndex == sizeof(cmd->len)) {
if (cmd->len) {
// not 0
cmd->data = (uint8_t*)calloc(cmd->len, 1);
if (cmd->data == nullptr) {
delete cmd;
flasherSerialState = FLASHER_WAIT_A;
}
flasherSerialState = FLASHER_WAIT_DATA;
} else {
// 0 len, so skip to CRC immediately
flasherSerialState = FLASHER_WAIT_CRCH;
}
}
break;
case FLASHER_WAIT_DATA:
flasherCRC += usbbyte;
cmd->data[flasherCmdDataIndex++] = usbbyte;
if (flasherCmdDataIndex == cmd->len) {
flasherSerialState = FLASHER_WAIT_CRCH;
}
break;
case FLASHER_WAIT_CRCH:
flasherCRC -= ((uint16_t)usbbyte << 8);
flasherSerialState = FLASHER_WAIT_CRCL;
break;
case FLASHER_WAIT_CRCL:
flasherCRC -= ((uint16_t)usbbyte);
if (flasherCRC) {
cmd = nullptr;
// we should probably delete the cmd and associated data here (data leak)
} else {
BaseType_t queuestatus = xQueueSend(flasherCmdQueue, &cmd, 0);
if (queuestatus == pdFALSE) {
if (cmd->data != nullptr) free(cmd->data);
delete cmd;
}
cmd = nullptr;
}
flasherSerialState = FLASHER_WAIT_A;
break;
}
}
}
void resetFlasherState() {
if (serialPassthroughState) {
Serial1.end();
}
serialPassthroughState = false;
}
static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
if (event_base == ARDUINO_USB_EVENTS) {
arduino_usb_event_data_t* data = (arduino_usb_event_data_t*)event_data;
switch (event_id) {
case ARDUINO_USB_STARTED_EVENT:
// Serial.println("USB PLUGGED");
resetFlasherState();
break;
case ARDUINO_USB_STOPPED_EVENT:
// Serial.println("USB UNPLUGGED");
resetFlasherState();
break;
case ARDUINO_USB_SUSPEND_EVENT:
// Serial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en);
break;
case ARDUINO_USB_RESUME_EVENT:
// Serial.println("USB RESUMED");
break;
default:
ets_printf("other USB event %d\n", event_id);
break;
}
} else if (event_base == ARDUINO_USB_CDC_EVENTS) {
arduino_usb_cdc_event_data_t* data = (arduino_usb_cdc_event_data_t*)event_data;
switch (event_id) {
case ARDUINO_USB_CDC_CONNECTED_EVENT:
ets_printf("CDC CONNECTED\n");
resetFlasherState();
usbConnectedStartTime = millis();
break;
case ARDUINO_USB_CDC_DISCONNECTED_EVENT:
ets_printf("CDC DISCONNECTED\n");
resetFlasherState();
break;
case ARDUINO_USB_CDC_LINE_STATE_EVENT:
ets_printf("CDC LINE STATE: dtr: %u, rts: %u\n", data->line_state.dtr, data->line_state.rts);
if (data->line_state.dtr == 0) resetFlasherState();
break;
case ARDUINO_USB_CDC_LINE_CODING_EVENT:
ets_printf("CDC LINE CODING: bit_rate: %u, data_bits: %u, stop_bits: %u, parity: %u\n", data->line_coding.bit_rate, data->line_coding.data_bits, data->line_coding.stop_bits, data->line_coding.parity);
resetFlasherState();
break;
case ARDUINO_USB_CDC_RX_EVENT:
// Serial.printf("CDC RX [%u]:", data->rx.len);
{
uint8_t buf[data->rx.len];
size_t len = USBSerial.read(buf, data->rx.len);
if (serialPassthroughState) {
Serial0.printf("IN-size=%d\n", len);
Serial1.write(buf, len);
quickBlink(1);
} else {
flasherUartHandler(buf, len);
}
}
break;
case ARDUINO_USB_CDC_RX_OVERFLOW_EVENT:
// Serial.printf("CDC RX Overflow of %d bytes", data->rx_overflow.dropped_bytes);
break;
default:
break;
}
}
}
typedef enum {
CMD_GET_VERSION = 1,
CMD_RESET_ESP = 2,
CMD_RESET = 11,
CMD_SET_POWER = 13,
CMD_ERASE_FLASH = 26,
CMD_ERASE_INFOPAGE = 27,
CMD_SAVE_MAC_FROM_FW = 40,
CMD_PASS_THROUGH = 50,
CMD_SELECT_ZBS243 = 60,
CMD_SELECT_NRF82511 = 61,
CMD_SELECT_PORT = 70,
CMD_READ_INFOPAGE = 80,
CMD_READ_FLASH = 81,
CMD_WRITE_INFOPAGE = 82,
CMD_WRITE_FLASH = 83,
CMD_AUTOFLASH = 87,
CMD_COMPLETE = 88,
} ZBS_UART_PROTO;
uint32_t FLASHER_VERSION = 0x00000030;
#define CONTROLLER_ZBS243 0
#define CONTROLLER_NRF82511 1
uint8_t selectedController = 0;
uint8_t selectedFlasherPort;
uint32_t currentFlasherOffset;
flasher* zbsflasherp;
nrfswd* nrfflasherp;
void processFlasherCommand(struct flasherCommand* cmd) {
uint8_t* tempbuffer;
uint8_t temp_buff[16];
uint32_t spi_speed = 0;
uint8_t powerPinCount = 1;
static uint32_t curspeed = 0;
switch (cmd->command) {
case CMD_GET_VERSION:
temp_buff[0] = FLASHER_VERSION >> 24;
temp_buff[1] = FLASHER_VERSION >> 16;
temp_buff[2] = FLASHER_VERSION >> 8;
temp_buff[3] = FLASHER_VERSION;
sendFlasherAnswer(cmd->command, temp_buff, 4);
break;
case CMD_RESET_ESP:
sendFlasherAnswer(cmd->command, NULL, 0);
delay(100);
ESP.restart();
break;
case CMD_SET_POWER:
powerControl(cmd->data[0], (uint8_t*)powerPins2, 4);
sendFlasherAnswer(CMD_SET_POWER, NULL, 0);
break;
case CMD_RESET:
if (zbsflasherp != nullptr) {
zbsflasherp->zbs->reset();
delete zbsflasherp;
zbsflasherp = nullptr;
} else if (nrfflasherp != nullptr) {
nrfflasherp->nrf_soft_reset();
delete nrfflasherp;
nrfflasherp = nullptr;
} else {
pinMode(FLASHER_EXT_RESET, OUTPUT);
digitalWrite(FLASHER_EXT_RESET, LOW);
vTaskDelay(200 / portTICK_PERIOD_MS);
digitalWrite(FLASHER_EXT_RESET, HIGH);
}
sendFlasherAnswer(CMD_RESET, NULL, 0);
break;
case CMD_ERASE_FLASH:
if (selectedController == CONTROLLER_NRF82511) {
} else if (selectedController == CONTROLLER_ZBS243) {
if (zbsflasherp == nullptr) return;
zbsflasherp->zbs->erase_flash();
}
sendFlasherAnswer(CMD_ERASE_FLASH, NULL, 0);
break;
case CMD_ERASE_INFOPAGE:
if (selectedController == CONTROLLER_NRF82511) {
nrfflasherp->erase_uicr();
} else if (selectedController == CONTROLLER_ZBS243) {
if (zbsflasherp == nullptr) return;
zbsflasherp->zbs->erase_infoblock();
}
sendFlasherAnswer(CMD_ERASE_INFOPAGE, NULL, 0);
break;
case CMD_SELECT_PORT:
selectedFlasherPort = cmd->data[0];
// Serial.printf("Port selected = %d\n", cmd->data[0]);
break;
case CMD_SELECT_ZBS243:
zbsflasherp = new flasher;
temp_buff[0] = zbsflasherp->connectTag(selectedFlasherPort);
sendFlasherAnswer(CMD_SELECT_ZBS243, temp_buff, 1);
currentFlasherOffset = 0;
selectedController = CONTROLLER_ZBS243;
break;
case CMD_SELECT_NRF82511:
powerControl(true, (uint8_t*)powerPins2, 4);
nrfflasherp = new nrfswd(FLASHER_EXT_MISO, FLASHER_EXT_CLK);
nrfflasherp->init();
temp_buff[0] = (nrfflasherp->isConnected && !nrfflasherp->isLocked);
sendFlasherAnswer(CMD_SELECT_NRF82511, temp_buff, 1);
currentFlasherOffset = 0;
selectedController = CONTROLLER_NRF82511;
break;
case CMD_READ_FLASH:
uint8_t* bufferp;
uint32_t cur_len;
if (selectedController == CONTROLLER_NRF82511) {
if (nrfflasherp == nullptr) return;
if (currentFlasherOffset >= nrfflasherp->nrf_info.flash_size) {
sendFlasherAnswer(CMD_COMPLETE, temp_buff, 1);
} else {
bufferp = (uint8_t*)malloc(256);
if (bufferp == nullptr) return;
cur_len = (nrfflasherp->nrf_info.flash_size - currentFlasherOffset >= 256) ? 256 : nrfflasherp->nrf_info.flash_size - currentFlasherOffset;
nrfflasherp->nrf_read_bank(currentFlasherOffset, (uint32_t*)bufferp, cur_len);
currentFlasherOffset += cur_len;
sendFlasherAnswer(CMD_READ_FLASH, bufferp, cur_len);
if (bufferp != nullptr) free(bufferp);
}
} else if (selectedController == CONTROLLER_ZBS243) {
if (zbsflasherp == nullptr) return;
if (currentFlasherOffset >= 65536) {
sendFlasherAnswer(CMD_COMPLETE, temp_buff, 1);
} else {
bufferp = (uint8_t*)malloc(256);
if (bufferp == nullptr) return;
cur_len = (65536 - currentFlasherOffset >= 256) ? 256 : 65536 - currentFlasherOffset;
zbsflasherp->readBlock(currentFlasherOffset, bufferp, cur_len, false);
currentFlasherOffset += cur_len;
sendFlasherAnswer(CMD_READ_FLASH, bufferp, cur_len);
if (bufferp != nullptr) free(bufferp);
}
} else {
Serial0.printf("No controller type selected\n");
}
break;
case CMD_READ_INFOPAGE:
uint8_t* ibufferp;
uint32_t icur_len;
if (selectedController == CONTROLLER_NRF82511) {
if (nrfflasherp == nullptr) return;
if (currentFlasherOffset >= 4096) {
sendFlasherAnswer(CMD_COMPLETE, temp_buff, 1);
} else {
ibufferp = (uint8_t*)malloc(256);
if (ibufferp == nullptr) return;
icur_len = (4096 - currentFlasherOffset >= 256) ? 256 : 4096 - currentFlasherOffset;
nrfflasherp->nrf_read_bank(0x10001000 + currentFlasherOffset, (uint32_t*)ibufferp, icur_len);
currentFlasherOffset += icur_len;
sendFlasherAnswer(CMD_READ_INFOPAGE, ibufferp, icur_len);
if (ibufferp != nullptr) free(ibufferp);
}
} else if (selectedController == CONTROLLER_ZBS243) {
if (zbsflasherp == nullptr) return;
if (currentFlasherOffset >= 256) {
sendFlasherAnswer(CMD_COMPLETE, temp_buff, 1);
} else {
ibufferp = (uint8_t*)malloc(256);
if (ibufferp == nullptr) return;
icur_len = (1024 - currentFlasherOffset >= 256) ? 256 : 1024 - currentFlasherOffset;
zbsflasherp->readBlock(currentFlasherOffset, ibufferp, icur_len, true);
currentFlasherOffset += icur_len;
sendFlasherAnswer(CMD_READ_INFOPAGE, ibufferp, icur_len);
if (ibufferp != nullptr) free(ibufferp);
}
}
break;
case CMD_WRITE_FLASH:
if (selectedController == CONTROLLER_NRF82511) {
if (nrfflasherp == nullptr) return;
if (currentFlasherOffset >= nrfflasherp->nrf_info.flash_size) {
sendFlasherAnswer(CMD_COMPLETE, temp_buff, 1);
} else {
for (uint32_t c = currentFlasherOffset; c < (currentFlasherOffset + cmd->len);) {
// very ugly and naive way to find out what page we're in, and erase all relevant pages before writing
if (c % nrfflasherp->nrf_info.codepage_size == 0) {
nrfflasherp->erase_page(c);
// Serial.printf("Erasing page %lu\n", c);
c += nrfflasherp->nrf_info.codepage_size;
} else {
c++;
}
}
nrfflasherp->nrf_write_bank(currentFlasherOffset, (uint32_t*)cmd->data, cmd->len);
// Serial.printf("wrote page to nrf\n");
currentFlasherOffset += cmd->len;
sendFlasherAnswer(CMD_WRITE_FLASH, NULL, 0);
}
} else if (selectedController == CONTROLLER_ZBS243) {
if (zbsflasherp == nullptr) return;
if (currentFlasherOffset >= 65536) {
sendFlasherAnswer(CMD_COMPLETE, temp_buff, 1);
} else {
zbsflasherp->writeBlock(currentFlasherOffset, cmd->data, cmd->len, false);
currentFlasherOffset += cmd->len;
sendFlasherAnswer(CMD_WRITE_FLASH, NULL, 0);
}
}
break;
case CMD_WRITE_INFOPAGE:
if (selectedController == CONTROLLER_NRF82511) {
if (nrfflasherp == nullptr) return;
if (currentFlasherOffset >= 4096) {
sendFlasherAnswer(CMD_COMPLETE, temp_buff, 1);
} else {
nrfflasherp->nrf_write_bank(0x10001000 + currentFlasherOffset, (uint32_t*)cmd->data, cmd->len);
// Serial.printf("wrote page to nrf\n");
currentFlasherOffset += cmd->len;
sendFlasherAnswer(CMD_WRITE_INFOPAGE, NULL, 0);
}
} else if (selectedController == CONTROLLER_ZBS243) {
if (zbsflasherp == nullptr) return;
if (currentFlasherOffset >= 1024) {
sendFlasherAnswer(CMD_COMPLETE, temp_buff, 1);
} else {
zbsflasherp->writeBlock(currentFlasherOffset, cmd->data, cmd->len, true);
currentFlasherOffset += cmd->len;
sendFlasherAnswer(CMD_WRITE_INFOPAGE, NULL, 0);
}
}
break;
case CMD_PASS_THROUGH:
Serial1.begin(115200, SERIAL_8N1, FLASHER_EXT_RXD, FLASHER_EXT_TXD);
USBSerial.println(">>>");
serialPassthroughState = true;
break;
case CMD_AUTOFLASH:
if (selectedController == CONTROLLER_ZBS243) {
autoFlash(zbsflasherp);
zbsflasherp->zbs->reset();
delete zbsflasherp;
zbsflasherp = 0;
USBSerial.write(0x04);
} else {
USBSerial.println("Not yet implemented!");
}
break;
}
}
uint32_t lastCmdTimeStamp = 0;
#define USBFLASHER_CONNECTION_TIMEOUT 5000
void flasherCommandTimeout() {
// this is triggered if no command has been received for a couple of seconds; this makes sure everything is cleaned up when the USB connection is lost
if (zbsflasherp != nullptr) {
delete zbsflasherp;
zbsflasherp = nullptr;
}
if (nrfflasherp != nullptr) {
delete nrfflasherp;
nrfflasherp = nullptr;
}
lastCmdTimeStamp = 0;
}
void tagDebugPassthrough() {
uint16_t len = Serial1.available();
if (len > 0) {
Serial0.printf("OUT-size=%d\n", len);
uint8_t* buf = (uint8_t*)malloc(len);
Serial1.read(buf, len);
USBSerial.write(buf, len);
free(buf);
}
}
void usbFlasherTask(void* parameter) {
flasherCmdQueue = xQueueCreate(10, sizeof(struct flasherCommand*));
#if ARDUINO_USB_MODEflash
#warning Wrong USB mode is in use, check settings in platformio.ini
#endif
USB.onEvent(usbEventCallback);
USBSerial.onEvent(usbEventCallback);
USBSerial.setTimeout(1000);
USB.begin();
USBSerial.begin();
struct flasherCommand* cmd;
while (true) {
while (serialPassthroughState) {
tagDebugPassthrough();
vTaskDelay(1 / portTICK_PERIOD_MS);
}
BaseType_t queuereceive = xQueueReceive(flasherCmdQueue, &cmd, 1000 / portTICK_PERIOD_MS); // timeout every second to make sure the timeout gets triggered after a while
if (queuereceive == pdTRUE) {
processFlasherCommand(cmd);
lastCmdTimeStamp = millis();
if (cmd->data != nullptr) {
free(cmd->data);
}
delete cmd;
} else {
if (lastCmdTimeStamp) {
if (millis() - lastCmdTimeStamp > USBFLASHER_CONNECTION_TIMEOUT)
flasherCommandTimeout();
}
}
}
}

View File

@@ -0,0 +1,222 @@
/* Autor: Aaron Christophel ATCnetz.de */
#include "zbs_interface.h"
#include <Arduino.h>
#include <SPI.h>
#include <stdint.h>
#include <stdio.h>
#ifdef USE_SOFTSPI
#include <SoftSPI.h>
#endif
#include "powermgt.h"
uint8_t ZBS_interface::begin(uint8_t SS, uint8_t CLK, uint8_t MOSI, uint8_t MISO, uint8_t RESET, uint8_t* POWER, uint8_t powerPins, uint32_t spi_speed) {
_SS_PIN = SS;
_CLK_PIN = CLK;
_MOSI_PIN = MOSI;
_MISO_PIN = MISO;
_RESET_PIN = RESET;
if (powerPins > 0)
_POWER_PIN = POWER;
else
_POWER_PIN = nullptr;
pinMode(_SS_PIN, OUTPUT);
pinMode(_RESET_PIN, OUTPUT);
digitalWrite(_SS_PIN, HIGH);
digitalWrite(_RESET_PIN, HIGH);
set_power(ZBS_ON);
pinMode(_CLK_PIN, OUTPUT);
pinMode(_MOSI_PIN, OUTPUT);
pinMode(_MISO_PIN, INPUT);
digitalWrite(_CLK_PIN, LOW);
digitalWrite(_MOSI_PIN, HIGH);
#ifdef USE_SOFTSPI
if (!spi) spi = new SoftSPI(_MOSI_PIN, _MISO_PIN, _CLK_PIN);
#else
if (!spi) spi = new SPIClass(HSPI);
#endif
spiSettings = SPISettings(spi_speed, MSBFIRST, SPI_MODE0);
spi_ready = 0;
if (spi_speed != 8000000) {
after_byte_delay = 10;
} else {
after_byte_delay = 10;
}
enable_debug();
return check_connection();
}
void ZBS_interface::setSpeed(uint32_t speed) {
spiSettings = SPISettings(speed, MSBFIRST, SPI_MODE0);
}
ZBS_interface::~ZBS_interface() {
if (spi) delete spi;
}
void ZBS_interface::set_power(uint8_t state) {
powerControl(state, _POWER_PIN, _POWER_PINS);
}
void ZBS_interface::enable_debug() {
digitalWrite(_RESET_PIN, HIGH);
digitalWrite(_SS_PIN, HIGH);
digitalWrite(_CLK_PIN, LOW);
digitalWrite(_MOSI_PIN, HIGH);
delay(30);
digitalWrite(_RESET_PIN, LOW);
delay(33);
digitalWrite(_CLK_PIN, HIGH);
delay(1);
digitalWrite(_CLK_PIN, LOW);
delay(1);
digitalWrite(_CLK_PIN, HIGH);
delay(1);
digitalWrite(_CLK_PIN, LOW);
delay(1);
digitalWrite(_CLK_PIN, HIGH);
delay(1);
digitalWrite(_CLK_PIN, LOW);
delay(1);
digitalWrite(_CLK_PIN, HIGH);
delay(1);
digitalWrite(_CLK_PIN, LOW);
delay(9);
digitalWrite(_RESET_PIN, HIGH);
delay(100);
}
void ZBS_interface::reset() {
if (spi) {
spi->end();
delete spi;
spi = nullptr;
}
pinMode(_SS_PIN, INPUT);
pinMode(_CLK_PIN, INPUT);
pinMode(_MOSI_PIN, INPUT);
pinMode(_MISO_PIN, INPUT);
digitalWrite(_RESET_PIN, LOW);
set_power(ZBS_OFF);
delay(500);
set_power(ZBS_ON);
delay(500);
digitalWrite(_RESET_PIN, HIGH);
pinMode(_RESET_PIN, INPUT);
}
void ZBS_interface::send_byte(uint8_t data) {
digitalWrite(_SS_PIN, LOW);
delayMicroseconds(5);
if (!spi_ready) {
spi_ready = 1;
spi->begin(_CLK_PIN, _MISO_PIN, _MOSI_PIN);
}
spi->beginTransaction(spiSettings);
spi->transfer(data);
spi->endTransaction();
delayMicroseconds(2);
digitalWrite(_SS_PIN, HIGH);
}
uint8_t ZBS_interface::read_byte() {
uint8_t data = 0x00;
digitalWrite(_SS_PIN, LOW);
delayMicroseconds(5);
if (!spi_ready) {
spi_ready = 1;
spi->begin(_CLK_PIN, _MISO_PIN, _MOSI_PIN);
}
spi->beginTransaction(spiSettings);
data = spi->transfer(0xff);
spi->endTransaction();
delayMicroseconds(2);
digitalWrite(_SS_PIN, HIGH);
return data;
}
void ZBS_interface::write_byte(uint8_t cmd, uint8_t addr, uint8_t data) {
send_byte(cmd);
send_byte(addr);
send_byte(data);
delayMicroseconds(after_byte_delay);
}
uint8_t ZBS_interface::read_byte(uint8_t cmd, uint8_t addr) {
uint8_t data = 0x00;
send_byte(cmd);
send_byte(addr);
data = read_byte();
delayMicroseconds(after_byte_delay);
return data;
}
void ZBS_interface::write_flash(uint16_t addr, uint8_t data) {
send_byte(ZBS_CMD_W_FLASH);
send_byte(addr >> 8);
send_byte(addr);
send_byte(data);
delayMicroseconds(after_byte_delay);
}
uint8_t ZBS_interface::read_flash(uint16_t addr) {
uint8_t data = 0x00;
send_byte(ZBS_CMD_R_FLASH);
send_byte(addr >> 8);
send_byte(addr);
data = read_byte();
delayMicroseconds(after_byte_delay);
return data;
}
void ZBS_interface::write_ram(uint8_t addr, uint8_t data) {
write_byte(ZBS_CMD_W_RAM, addr, data);
}
uint8_t ZBS_interface::read_ram(uint8_t addr) {
return read_byte(ZBS_CMD_R_RAM, addr);
}
void ZBS_interface::write_sfr(uint8_t addr, uint8_t data) {
write_byte(ZBS_CMD_W_SFR, addr, data);
}
uint8_t ZBS_interface::read_sfr(uint8_t addr) {
return read_byte(ZBS_CMD_R_SFR, addr);
}
uint8_t ZBS_interface::check_connection() {
uint8_t test_byte = 0xA5;
write_ram(0xba, test_byte);
delay(1);
return read_ram(0xba) == test_byte;
}
uint8_t ZBS_interface::select_flash(uint8_t page) {
uint8_t sfr_low_bank = page ? 0x80 : 0x00;
write_sfr(0xd8, sfr_low_bank);
delay(1);
return read_sfr(0xd8) == sfr_low_bank;
}
void ZBS_interface::erase_flash() {
send_byte(ZBS_CMD_ERASE_FLASH);
send_byte(0x00);
send_byte(0x00);
send_byte(0x00);
delay(100);
}
void ZBS_interface::erase_infoblock() {
send_byte(ZBS_CMD_ERASE_INFOBLOCK);
send_byte(0x00);
send_byte(0x00);
send_byte(0x00);
delay(100);
}

View File

@@ -106,15 +106,16 @@ def validate_arguments(args):
return False
if args.command == "write" and not os.path.isfile(args.filename):
print("Couldn't find the specified file!")
return False;
return False
if args.command in ["read", "write"] and not args.filename:
print("Please specify a file to save read data")
return False;
return False
if args.command == "read" and len(args.filename) < 2:
print("Please specify a file to save read data")
return False;
return False
return True
def read_from_serial(port, filename, flash):
if flash:
print(
@@ -145,6 +146,7 @@ def read_from_serial(port, filename, flash):
else:
print("Failed reading block, timeout?")
def write_to_serial(port, filename, flash):
if flash:
@@ -167,7 +169,7 @@ def write_to_serial(port, filename, flash):
else:
print(f"Writing info page data from file: {filename}\n")
chunk_size = 1024
chunk_size = 256
if filename.endswith('.bin'):
file_data = read_binary_file(filename)
@@ -192,6 +194,7 @@ def write_to_serial(port, filename, flash):
return
print('\rAll done writing! ', end='', flush=True)
def short_passthough(period_time):
start_time = time.time()
while time.time() - start_time < period_time:
@@ -201,6 +204,7 @@ def short_passthough(period_time):
if chr(0x04) in data.decode():
break
def main():
try:
parser = argparse.ArgumentParser(
@@ -224,7 +228,7 @@ def main():
help="Selects the external(side) port")
parser.add_argument("--altradio", action="store_true",
help="Selects the alternate radio port")
parser.add_argument("--pt","--passthrough", action="store_true",
parser.add_argument("--pt", "--passthrough", action="store_true",
help="Enters serial passthrough for debug output after flashing")
args = parser.parse_args()
@@ -237,7 +241,7 @@ def main():
return
global ser
ser = serial.Serial(args.port, baudrate=500000)
ser = serial.Serial(args.port, baudrate=115200)
time.sleep(1) # Flush serial data
while (ser.inWaiting() > 0):
data_str = ser.read(ser.inWaiting())
@@ -251,8 +255,9 @@ def main():
print(
"Couldn't establish a connection with the flasher, did you select the correct serial port?")
exit(0)
if (args.command!="debug"):
send_cmd(CMD_SET_POWER, bytearray([1]))
cmd, answer = wait_for_command()
if (args.command != "debug"):
if args.internalap:
send_cmd(CMD_SELECT_PORT, bytearray([0]))
if args.external:
@@ -264,8 +269,9 @@ def main():
send_cmd(CMD_SELECT_NRF82511, bytearray([]))
if args.zbs243:
send_cmd(CMD_SELECT_ZBS243, bytearray([]))
cmd, answer = wait_for_command()
# send_cmd(CMD_SET_POWER, bytearray([1]))
# cmd, answer = wait_for_command()
if (answer[0] == 1):
print("Connection established to microcontroller")
else:
@@ -278,22 +284,20 @@ def main():
write_to_serial(ser, args.filename, args.flash)
elif args.command == "autoflash":
print("Starting automatic tag flash")
send_cmd(CMD_AUTOFLASH , bytearray([]))
send_cmd(CMD_AUTOFLASH, bytearray([]))
short_passthough(30)
else:
print("Invalid command!")
send_cmd(CMD_RESET, bytearray([]))
cmd, answer = wait_for_command()
send_cmd(CMD_SET_POWER, bytearray([1]))
cmd, answer = wait_for_command()
if (args.pt or args.command=="debug"):
if (args.pt or args.command == "debug"):
# enter passthrough mode
send_cmd(CMD_PASS_THROUGH , bytearray([]))
print("Now showing debug output from the tag - CTRL+C to quit");
print("---------------------------------------------------------------------------------");
send_cmd(CMD_PASS_THROUGH, bytearray([]))
print("Now showing debug output from the tag - CTRL+C to quit")
print(
"---------------------------------------------------------------------------------")
while True:
try:
data = ser.read()
@@ -307,7 +311,6 @@ def main():
if chr(0x04) in data.decode():
break
except KeyboardInterrupt:
print("\nBye!")
ser.close()