Merge pull request #90 from jjwbruijn/New_Flasher

New flasher
This commit is contained in:
Jelmer
2023-07-23 12:12:53 +02:00
committed by GitHub
10 changed files with 1241 additions and 346 deletions

View File

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

View File

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

View File

@@ -1,8 +0,0 @@
#include <Arduino.h>
extern QueueHandle_t consoleCmdQueue;
extern TaskHandle_t consoleTaskHandle;
void consoleStopTask();
void consoleTask(void* parameter);
void consoleUartHandler(uint8_t* data, uint8_t len);

View File

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

View File

@@ -65,7 +65,7 @@ build_flags =
-D FLASHER_LED=15
-D FLASHER_RGB_LED=33
build_src_filter =
+<*>-<usbflasher.cpp>-<serialconsole.cpp>
+<*>-<usbflasher.cpp>-<swd.cpp>
board_build.psram_type=qspi_opi
board_upload.maximum_size = 4194304
board_upload.maximum_ram_size = 327680
@@ -100,7 +100,7 @@ build_flags =
-D FLASHER_LED=15
-D FLASHER_RGB_LED=-1
build_src_filter =
+<*>-<usbflasher.cpp>-<serialconsole.cpp>
+<*>-<usbflasher.cpp>-<swd.cpp>
board_build.psram_type=qspi_opi
board_upload.maximum_size = 4194304
board_upload.maximum_ram_size = 327680
@@ -187,7 +187,7 @@ build_flags =
-D FLASHER_AP_RXD=16
-D FLASHER_LED=22
build_src_filter =
+<*>-<usbflasher.cpp>-<serialconsole.cpp>
+<*>-<usbflasher.cpp>-<swd.cpp>
; ----------------------------------------------------------------------------------------
; !!! this configuration expects an wemos_d1_mini32
@@ -213,7 +213,7 @@ build_flags =
-D FLASHER_AP_RXD=17
-D FLASHER_LED=22
build_src_filter =
+<*>-<usbflasher.cpp>-<serialconsole.cpp>
+<*>-<usbflasher.cpp>-<swd.cpp>
; ----------------------------------------------------------------------------------------
; !!! this configuration expects an m5stack esp32
@@ -250,4 +250,4 @@ build_flags =
-D ILI9341_DRIVER
-D SMOOTH_FONT
build_src_filter =
+<*>-<usbflasher.cpp>-<serialconsole.cpp>
+<*>-<usbflasher.cpp>-<swd.cpp>

View File

@@ -2,9 +2,10 @@
#include <Arduino.h>
#include <ArduinoJson.h>
#include "storage.h"
#include "LittleFS.h"
#include <MD5Builder.h>
#include "LittleFS.h"
#include "storage.h"
// #include <FS.h>
#include "leds.h"
@@ -61,53 +62,6 @@ uint8_t pinsExt[] = {FLASHER_EXT_CLK, FLASHER_EXT_MISO, FLASHER_EXT_MOSI, FLASHE
#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 readInfoBlock();
bool writeInfoBlock();
protected:
bool writeBlock256(uint16_t offset, uint8_t *flashbuffer);
void get_mac_format1();
void get_mac_format2();
};
flasher::flasher() {
zbs = new ZBS_interface;
Storage.end();
@@ -519,6 +473,34 @@ bool flasher::writeFlashFromPack(String filename, uint8_t type) {
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;
}
uint16_t getAPUpdateVersion(uint8_t type) {
StaticJsonDocument<512> doc;
DynamicJsonDocument APconfig(512);

View File

@@ -1,118 +0,0 @@
#include "serialconsole.h"
#include <Arduino.h>
#include "USB.h"
QueueHandle_t consoleCmdQueue;
TaskHandle_t consoleTaskHandle;
extern USBCDC USBSerial;
struct consoleCommand {
uint8_t command = 0;
uint8_t len = 0;
uint8_t* data = nullptr;
};
void consoleStopTask() {
if (consoleTaskHandle) vTaskDelete(consoleTaskHandle);
consoleTaskHandle = NULL;
}
/*
.in>1B 5B 3C 30 3B 33 39 3B 39 4D
,in>1B 5B 3C 30 3B 33 39 3B 39 6D
,in>1B 5B 3C 32 3B 33 39 3B 39 4D
,in>1B 5B 3C 32 3B 33 39 3B 39 6D
in>1B 5B 3C 30 3B 32 38 3B 31 32 4D
in>1B 5B 3C 30 3B 32 38 3B 31 32 6D
in>1B 5B 3C 32 3B 32 38 3B 31 32 4D
in>1B 5B 3C 32 3B 32 38 3B 31 32 6D
in>1B 5B 3C 36 34 3B 32 39 3B 31 32 4D
in>1B 5B 3C 36 35 3B 32 39 3B 31 32 4D
*/
bool escapeCommandComplete(struct consoleCommand* cmd) {
return true;
}
void consoleUartHandler(uint8_t* data, uint8_t len) {
static struct consoleCommand* cmd = nullptr;
static bool commandStarted = false;
while (len--) {
uint8_t usbbyte = *(data++);
if (cmd == nullptr) {
cmd = new struct consoleCommand;
cmd->data = (uint8_t*)calloc(65, 1);
cmd->len = 0;
}
// check if we've started a command in this byte
if ((!commandStarted) && (usbbyte == 0x1B)) {
commandStarted = true;
if (cmd->len != 0) {
BaseType_t queuestatus = xQueueSend(consoleCmdQueue, &cmd, 0);
if (queuestatus == pdFALSE) {
if (cmd->data != nullptr) free(cmd->data);
delete cmd;
}
cmd = nullptr;
}
}
if (cmd == nullptr) {
cmd = new struct consoleCommand;
cmd->data = (uint8_t*)calloc(65, 1);
cmd->len = 0;
}
cmd->data[cmd->len++] = usbbyte;
cmd->len %= 64;
if (commandStarted) {
if (escapeCommandComplete(cmd) || cmd->len == 0x00) {
BaseType_t queuestatus = xQueueSend(consoleCmdQueue, &cmd, 0);
if (queuestatus == pdFALSE) {
if (cmd->data != nullptr) free(cmd->data);
delete cmd;
}
commandStarted = false;
cmd = nullptr;
}
}
}
if (!commandStarted && cmd != nullptr) {
BaseType_t queuestatus = xQueueSend(consoleCmdQueue, &cmd, 0);
if (queuestatus == pdFALSE) {
if (cmd->data != nullptr) free(cmd->data);
delete cmd;
}
cmd = nullptr;
}
}
void consoleTask(void* parameter) {
struct consoleCommand* cmd;
USBSerial.print("\e[?1000;1006;1015h"); // works
while (true) {
BaseType_t queuereceive = xQueueReceive(consoleCmdQueue, &cmd, 1500 / portTICK_PERIOD_MS);
if (queuereceive == pdTRUE) {
uint8_t c = 0;
Serial.printf("queue>");
while (cmd->len--) {
Serial.printf(" %02X", cmd->data[c]);
c++;
}
if (cmd->data != nullptr) free(cmd->data);
delete cmd;
Serial.printf("\n");
}
}
}

View File

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

View File

@@ -1,9 +1,10 @@
#include <Arduino.h>
#include "USB.h"
#include "flasher.h"
#include "powermgt.h"
#include "serialconsole.h"
#include "settings.h"
#include "swd.h"
#include "zbs_interface.h"
USBCDC USBSerial;
@@ -11,6 +12,7 @@ USBCDC USBSerial;
QueueHandle_t flasherCmdQueue;
uint32_t usbConnectedStartTime = 0;
bool serialPassthroughState = false;
#define FLASHER_WAIT_A 0
#define FLASHER_WAIT_T 1
@@ -22,55 +24,101 @@ uint32_t usbConnectedStartTime = 0;
struct flasherCommand {
uint8_t command = 0;
uint8_t len = 0;
uint32_t len = 0;
uint8_t* data = nullptr;
};
#define FLASHER_MODE_UNKNOWN 0
#define FLASHER_MODE_FLASHER 1
#define FLASHER_MODE_CONSOLE 2
volatile uint8_t usbFlasherMode = FLASHER_MODE_UNKNOWN;
void enterConsoleMode() {
usbFlasherMode = FLASHER_MODE_CONSOLE;
xTaskCreate(consoleTask, "consoleTask", 10000, NULL, 2, &consoleTaskHandle);
}
int8_t powerPins[] = FLASHER_AP_POWER;
#ifdef OPENEPAPERLINK_PCB
int8_t powerPins2[] = FLASHER_EXT_POWER;
int8_t powerPins3[] = FLASHER_ALT_POWER;
#endif
void sendFlasherAnswer(uint8_t answer_cmd, uint8_t* ans_buff, uint8_t len) {
uint8_t* answer_buffer = (uint8_t*)calloc(2 + 2 + len + 2, 1);
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;
answer_buffer[3] = len;
CRC_value += len;
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[4 + i] = ans_buff[i];
answer_buffer[7 + i] = ans_buff[i];
CRC_value += ans_buff[i];
}
answer_buffer[2 + 2 + len] = CRC_value >> 8;
answer_buffer[2 + 2 + len + 1] = CRC_value;
USBSerial.write(answer_buffer, 2 + 2 + len + 2);
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 uint8_t flasherCmdDataIndex = 0;
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--) {
@@ -81,7 +129,7 @@ void flasherUartHandler(uint8_t* data, uint8_t len) {
flasherSerialState = FLASHER_WAIT_T;
flasherLastCmd = millis();
} else {
enterConsoleMode();
// enterConsoleMode();
}
break;
case FLASHER_WAIT_T:
@@ -98,15 +146,25 @@ void flasherUartHandler(uint8_t* data, uint8_t len) {
cmd->command = usbbyte;
flasherCRC += usbbyte;
flasherSerialState = FLASHER_WAIT_LEN;
curLenIndex = 0;
break;
case FLASHER_WAIT_LEN:
flasherCRC += usbbyte;
if (usbbyte) {
cmd->len = usbbyte;
cmd->data = (uint8_t*)calloc(usbbyte, 1);
flasherSerialState = FLASHER_WAIT_DATA;
} else {
flasherSerialState = FLASHER_WAIT_CRCH;
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:
@@ -123,10 +181,9 @@ void flasherUartHandler(uint8_t* data, uint8_t len) {
case FLASHER_WAIT_CRCL:
flasherCRC -= ((uint16_t)usbbyte);
if (flasherCRC) {
Serial.printf("CRC failed for flasher command :( %04X\n", flasherCRC);
cmd = nullptr;
// we should probably delete the cmd and associated data here (data leak)
} else {
if (usbFlasherMode == FLASHER_MODE_UNKNOWN) usbFlasherMode = FLASHER_MODE_FLASHER;
BaseType_t queuestatus = xQueueSend(flasherCmdQueue, &cmd, 0);
if (queuestatus == pdFALSE) {
if (cmd->data != nullptr) free(cmd->data);
@@ -141,12 +198,10 @@ void flasherUartHandler(uint8_t* data, uint8_t len) {
}
void resetFlasherState() {
if (usbFlasherMode != FLASHER_MODE_UNKNOWN) {
if (usbFlasherMode == FLASHER_MODE_CONSOLE) consoleStopTask();
Serial.print("Resetting flasher state");
usbFlasherMode = FLASHER_MODE_UNKNOWN;
usbConnectedStartTime = millis();
if (serialPassthroughState) {
Serial2.end();
}
serialPassthroughState = false;
}
static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
@@ -196,11 +251,7 @@ static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t eve
{
uint8_t buf[data->rx.len];
size_t len = USBSerial.read(buf, data->rx.len);
if (usbFlasherMode != FLASHER_MODE_CONSOLE) {
flasherUartHandler(buf, len);
} else {
consoleUartHandler(buf, len);
}
flasherUartHandler(buf, len);
}
break;
case ARDUINO_USB_CDC_RX_OVERFLOW_EVENT:
@@ -216,24 +267,36 @@ static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t eve
typedef enum {
CMD_GET_VERSION = 1,
CMD_RESET_ESP = 2,
CMD_ZBS_BEGIN = 10,
CMD_RESET_ZBS = 11,
CMD_SELECT_PAGE = 12,
CMD_RESET = 11,
CMD_SET_POWER = 13,
CMD_READ_RAM = 20,
CMD_WRITE_RAM = 21,
CMD_READ_FLASH = 22,
CMD_WRITE_FLASH = 23,
CMD_READ_SFR = 24,
CMD_WRITE_SFR = 25,
CMD_ERASE_FLASH = 26,
CMD_ERASE_INFOBLOCK = 27,
CMD_ERASE_INFOPAGE = 27,
CMD_SAVE_MAC_FROM_FW = 40,
CMD_PASS_THROUGH = 50,
} ZBS_UART_PROTO;
uint32_t FLASHER_VERSION = 0x0000002F;
static class ZBS_interface* zbs = nullptr;
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;
@@ -255,128 +318,246 @@ void processFlasherCommand(struct flasherCommand* cmd) {
delay(100);
ESP.restart();
break;
case CMD_ZBS_BEGIN:
if (zbs != nullptr) {
delete zbs;
}
zbs = new ZBS_interface;
if (cmd->data[0] & 1) {
spi_speed = 1000000;
} else {
spi_speed = 8000000;
}
curspeed = spi_speed;
if (cmd->data[0] & 2) {
powerPinCount = powerPins[0] != -1 ? sizeof(powerPins) : 0;
temp_buff[0] = zbs->begin(FLASHER_AP_SS, FLASHER_AP_CLK, FLASHER_AP_MOSI, FLASHER_AP_MISO, FLASHER_AP_RESET, (uint8_t*)powerPins, powerPinCount, spi_speed);
} else if (cmd->data[0] & 4) {
#ifdef OPENEPAPERLINK_PCB
powerPinCount = powerPins3[0] != -1 ? sizeof(powerPins3) : 0;
temp_buff[0] = zbs->begin(FLASHER_ALT_SS, FLASHER_ALT_CLK, FLASHER_ALT_MOSI, FLASHER_ALT_MISO, FLASHER_ALT_RESET, (uint8_t*)powerPins3, powerPinCount, spi_speed);
#endif
} else {
#ifdef OPENEPAPERLINK_PCB
powerPinCount = powerPins2[0] != -1 ? sizeof(powerPins2) : 0;
temp_buff[0] = zbs->begin(FLASHER_EXT_SS, FLASHER_EXT_CLK, FLASHER_EXT_MOSI, FLASHER_EXT_MISO, FLASHER_EXT_RESET, (uint8_t*)powerPins2, powerPinCount, spi_speed);
#endif
}
sendFlasherAnswer(cmd->command, temp_buff, 1);
break;
case CMD_RESET_ZBS:
zbs->reset();
temp_buff[0] = 1;
sendFlasherAnswer(cmd->command, temp_buff, 1);
break;
case CMD_SELECT_PAGE:
temp_buff[0] = zbs->select_flash(cmd->data[0] ? 1 : 0);
sendFlasherAnswer(cmd->command, temp_buff, 1);
break;
case CMD_SET_POWER:
zbs->set_power(cmd->data[0] ? 1 : 0);
temp_buff[0] = 1;
sendFlasherAnswer(cmd->command, temp_buff, 1);
break;
case CMD_READ_RAM:
temp_buff[0] = zbs->read_ram(cmd->data[0]);
sendFlasherAnswer(cmd->command, temp_buff, 1);
break;
case CMD_WRITE_RAM:
zbs->write_ram(cmd->data[0], cmd->data[1]);
temp_buff[0] = 1;
sendFlasherAnswer(cmd->command, temp_buff, 1);
break;
case CMD_READ_FLASH:
tempbuffer = (uint8_t*)calloc(cmd->data[0], 1);
// cmd_buff[0] = len
// cmd_buff[1] << 8 | cmd_buff[2] = position
// Serial.printf("Loading %d bytes from %04X \n", cmd->data[0], (cmd->data[1] << 8 | cmd->data[2]));
for (int i = 0; i < cmd->data[0]; i++) {
tempbuffer[i] = zbs->read_flash((cmd->data[1] << 8 | cmd->data[2]) + i);
}
sendFlasherAnswer(cmd->command, tempbuffer, cmd->data[0]);
free(tempbuffer);
break;
case CMD_WRITE_FLASH:
// cmd_buff[0] = len
// cmd_buff[1] << 8 | cmd_buff[2] = position
// cmd_buff[3+i] = data
if (cmd->data[0] >= (0xff - 3)) { // Len too high, only 0xFF - header len possible
temp_buff[0] = 0xEE;
sendFlasherAnswer(cmd->command, temp_buff, 1);
break;
}
// Serial.printf("Writing %d bytes to %04X \n", cmd->data[0], (cmd->data[1] << 8 | cmd->data[2]));
for (int i = 0; i < cmd->data[0]; i++) {
if (cmd->data[3 + i] != 0xff) {
for (uint8_t attempts = 0; attempts < 10; attempts++) {
zbs->write_flash((cmd->data[1] << 8 | cmd->data[2]) + i, cmd->data[3 + i]);
if (zbs->read_flash((cmd->data[1] << 8 | cmd->data[2]) + i) == cmd->data[3 + i]) {
goto flash_pass;
}
curspeed -= 100000;
zbs->setSpeed(curspeed);
}
flash_fail:
temp_buff[0] = 0;
sendFlasherAnswer(cmd->command, temp_buff, 1);
switch (selectedFlasherPort) {
case 0:
powerControl(cmd->data[0], (uint8_t*)powerPins, 1);
break;
case 1:
powerControl(cmd->data[0], (uint8_t*)powerPins2, 1);
break;
case 2:
powerControl(cmd->data[0], (uint8_t*)powerPins3, 1);
break;
flash_pass:
continue;
}
}
temp_buff[0] = 1;
sendFlasherAnswer(cmd->command, temp_buff, 1);
sendFlasherAnswer(CMD_SET_POWER, NULL, 0);
break;
case CMD_READ_SFR:
temp_buff[0] = zbs->read_sfr(cmd->data[0]);
sendFlasherAnswer(cmd->command, temp_buff, 1);
break;
case CMD_WRITE_SFR:
zbs->write_sfr(cmd->data[0], cmd->data[1]);
temp_buff[0] = 1;
sendFlasherAnswer(cmd->command, temp_buff, 1);
case CMD_RESET:
if (zbsflasherp != nullptr) {
zbsflasherp->zbs->reset();
delete zbsflasherp;
zbsflasherp = nullptr;
}
if (nrfflasherp != nullptr) {
nrfflasherp->nrf_soft_reset();
delete nrfflasherp;
nrfflasherp = nullptr;
}
sendFlasherAnswer(CMD_RESET, NULL, 0);
break;
case CMD_ERASE_FLASH:
zbs->erase_flash();
temp_buff[0] = 1;
sendFlasherAnswer(cmd->command, temp_buff, 1);
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_INFOBLOCK:
zbs->erase_infoblock();
temp_buff[0] = 1;
sendFlasherAnswer(cmd->command, temp_buff, 1);
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:
switch (selectedFlasherPort) {
case 0:
powerControl(true, (uint8_t*)powerPins, 1);
nrfflasherp = new nrfswd(FLASHER_AP_MISO, FLASHER_AP_CLK);
break;
case 1:
powerControl(true, (uint8_t*)powerPins2, 1);
nrfflasherp = new nrfswd(FLASHER_EXT_MISO, FLASHER_EXT_CLK);
break;
case 2:
powerControl(true, (uint8_t*)powerPins3, 1);
nrfflasherp = new nrfswd(FLASHER_ALT_MISO, FLASHER_ALT_CLK);
break;
}
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(1024);
if (bufferp == nullptr) return;
cur_len = (nrfflasherp->nrf_info.flash_size - currentFlasherOffset >= 1024) ? 1024 : 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(1024);
if (bufferp == nullptr) return;
cur_len = (65536 - currentFlasherOffset >= 1024) ? 1024 : 65536 - currentFlasherOffset;
zbsflasherp->readBlock(currentFlasherOffset, bufferp, cur_len, false);
currentFlasherOffset += cur_len;
sendFlasherAnswer(CMD_READ_FLASH, bufferp, cur_len);
if (bufferp != nullptr) free(bufferp);
}
}
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(1024);
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 >= 1024) {
sendFlasherAnswer(CMD_COMPLETE, temp_buff, 1);
} else {
ibufferp = (uint8_t*)malloc(1024);
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_SAVE_MAC_FROM_FW:
case CMD_PASS_THROUGH:
Serial2.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 = Serial2.available();
if (len > 0) {
uint8_t* buf = (uint8_t*)malloc(len);
Serial2.read(buf, len);
Serial.write(buf, len);
USBSerial.write(buf, len);
free(buf);
}
}
void usbFlasherTask(void* parameter) {
flasherCmdQueue = xQueueCreate(10, sizeof(struct flasherCommand*));
consoleCmdQueue = xQueueCreate(10, sizeof(struct consoleCommand*));
#if ARDUINO_USB_MODE
#if ARDUINO_USB_MODEflash
#warning Wrong USB mode is in use, check settings in platformio.ini
#endif
USB.onEvent(usbEventCallback);
@@ -387,13 +568,23 @@ void usbFlasherTask(void* parameter) {
struct flasherCommand* cmd;
while (true) {
BaseType_t queuereceive = xQueueReceive(flasherCmdQueue, &cmd, portMAX_DELAY);
while (serialPassthroughState) {
tagDebugPassthrough();
vTaskDelay(10 / portTICK_PERIOD_MS);
}
BaseType_t queuereceive = xQueueReceive(flasherCmdQueue, &cmd, 1000 / portTICK_PERIOD_MS); // timeout every second to make sure the timeout gets triggered after a while
if (queuereceive == pdTRUE) {
processFlasherCommand(cmd);
lastCmdTimeStamp = millis();
if (cmd->data != nullptr) {
free(cmd->data);
}
delete cmd;
} else {
if (lastCmdTimeStamp) {
if (millis() - lastCmdTimeStamp > USBFLASHER_CONNECTION_TIMEOUT)
flasherCommandTimeout();
}
}
}
}

View File

@@ -8,7 +8,7 @@
#include <stdio.h>
#ifdef USE_SOFTSPI
#include <SoftSPI.h>
#include <SoftSPI.h>
#endif
#include "powermgt.h"
@@ -40,7 +40,6 @@ uint8_t ZBS_interface::begin(uint8_t SS, uint8_t CLK, uint8_t MOSI, uint8_t MISO
if (!spi) spi = new SPIClass(HSPI);
#endif
spiSettings = SPISettings(spi_speed, MSBFIRST, SPI_MODE0);
spi_ready = 0;
@@ -58,7 +57,7 @@ void ZBS_interface::setSpeed(uint32_t speed) {
}
ZBS_interface::~ZBS_interface() {
if(spi)delete spi;
if (spi) delete spi;
}
void ZBS_interface::set_power(uint8_t state) {
powerControl(state, _POWER_PIN, _POWER_PINS);
@@ -93,7 +92,11 @@ void ZBS_interface::enable_debug() {
}
void ZBS_interface::reset() {
spi->end();
if (spi) {
spi->end();
delete spi;
spi = nullptr;
}
pinMode(_SS_PIN, INPUT);
pinMode(_CLK_PIN, INPUT);
pinMode(_MOSI_PIN, INPUT);