mirror of
https://github.com/OpenEPaperLink/OpenEPaperLink.git
synced 2026-03-21 06:06:23 +01:00
Added the tag-flasher
This commit is contained in:
@@ -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()
|
||||
4
Tag_Flasher/ESP32_Flasher/.clang-format
Normal file
4
Tag_Flasher/ESP32_Flasher/.clang-format
Normal file
@@ -0,0 +1,4 @@
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
IndentWidth: 4
|
||||
ColumnLimit: 0
|
||||
5
Tag_Flasher/ESP32_Flasher/.gitignore
vendored
Normal file
5
Tag_Flasher/ESP32_Flasher/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
||||
10
Tag_Flasher/ESP32_Flasher/.vscode/extensions.json
vendored
Normal file
10
Tag_Flasher/ESP32_Flasher/.vscode/extensions.json
vendored
Normal 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"
|
||||
]
|
||||
}
|
||||
55
Tag_Flasher/ESP32_Flasher/.vscode/settings.json
vendored
Normal file
55
Tag_Flasher/ESP32_Flasher/.vscode/settings.json
vendored
Normal 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"
|
||||
}
|
||||
}
|
||||
3
Tag_Flasher/ESP32_Flasher/CMakeLists.txt
Normal file
3
Tag_Flasher/ESP32_Flasher/CMakeLists.txt
Normal file
@@ -0,0 +1,3 @@
|
||||
cmake_minimum_required(VERSION 3.16.0)
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(esp32_fw)
|
||||
59
Tag_Flasher/ESP32_Flasher/include/flasher.h
Normal file
59
Tag_Flasher/ESP32_Flasher/include/flasher.h
Normal 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();
|
||||
};
|
||||
37
Tag_Flasher/ESP32_Flasher/include/leds.h
Normal file
37
Tag_Flasher/ESP32_Flasher/include/leds.h
Normal 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);
|
||||
5
Tag_Flasher/ESP32_Flasher/include/powermgt.h
Normal file
5
Tag_Flasher/ESP32_Flasher/include/powermgt.h
Normal file
@@ -0,0 +1,5 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
|
||||
//void doLeds();
|
||||
void powerControl(bool powerState, uint8_t* pin, uint8_t pincount);
|
||||
9
Tag_Flasher/ESP32_Flasher/include/settings.h
Normal file
9
Tag_Flasher/ESP32_Flasher/include/settings.h
Normal 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
|
||||
42
Tag_Flasher/ESP32_Flasher/include/storage.h
Normal file
42
Tag_Flasher/ESP32_Flasher/include/storage.h
Normal 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
|
||||
|
||||
|
||||
83
Tag_Flasher/ESP32_Flasher/include/swd.h
Normal file
83
Tag_Flasher/ESP32_Flasher/include/swd.h
Normal 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);
|
||||
};
|
||||
4
Tag_Flasher/ESP32_Flasher/include/usbflasher.h
Normal file
4
Tag_Flasher/ESP32_Flasher/include/usbflasher.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#include <Arduino.h>
|
||||
|
||||
|
||||
void usbFlasherTask(void* parameter);
|
||||
64
Tag_Flasher/ESP32_Flasher/include/zbs_interface.h
Normal file
64
Tag_Flasher/ESP32_Flasher/include/zbs_interface.h
Normal 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;
|
||||
};
|
||||
64
Tag_Flasher/ESP32_Flasher/platformio.ini
Normal file
64
Tag_Flasher/ESP32_Flasher/platformio.ini
Normal 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
|
||||
6
Tag_Flasher/ESP32_Flasher/src/CMakeLists.txt
Normal file
6
Tag_Flasher/ESP32_Flasher/src/CMakeLists.txt
Normal 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})
|
||||
540
Tag_Flasher/ESP32_Flasher/src/flasher.cpp
Normal file
540
Tag_Flasher/ESP32_Flasher/src/flasher.cpp
Normal 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;
|
||||
}
|
||||
331
Tag_Flasher/ESP32_Flasher/src/leds.cpp
Normal file
331
Tag_Flasher/ESP32_Flasher/src/leds.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
51
Tag_Flasher/ESP32_Flasher/src/main.cpp
Normal file
51
Tag_Flasher/ESP32_Flasher/src/main.cpp
Normal 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);
|
||||
}
|
||||
31
Tag_Flasher/ESP32_Flasher/src/powermgt.cpp
Normal file
31
Tag_Flasher/ESP32_Flasher/src/powermgt.cpp
Normal 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);
|
||||
|
||||
}
|
||||
216
Tag_Flasher/ESP32_Flasher/src/storage.cpp
Normal file
216
Tag_Flasher/ESP32_Flasher/src/storage.cpp
Normal 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;
|
||||
393
Tag_Flasher/ESP32_Flasher/src/swd.cpp
Normal file
393
Tag_Flasher/ESP32_Flasher/src/swd.cpp
Normal 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;
|
||||
}
|
||||
582
Tag_Flasher/ESP32_Flasher/src/usbflasher.cpp
Normal file
582
Tag_Flasher/ESP32_Flasher/src/usbflasher.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
222
Tag_Flasher/ESP32_Flasher/src/zbs_interface.cpp
Normal file
222
Tag_Flasher/ESP32_Flasher/src/zbs_interface.cpp
Normal 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);
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user