IP Configuration
This commit is contained in:
335
lib/WiFiNINA/examples/Tools/FirmwareUpdater/ESP32BootROM.cpp
Normal file
335
lib/WiFiNINA/examples/Tools/FirmwareUpdater/ESP32BootROM.cpp
Normal file
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
ESP32BootROM - part of the Firmware Updater for the
|
||||
Arduino MKR WiFi 1010, Arduino MKR Vidor 4000, and Arduino UNO WiFi Rev.2.
|
||||
|
||||
Copyright (c) 2018 Arduino SA. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifdef ARDUINO_SAMD_MKRVIDOR4000
|
||||
#include <VidorPeripherals.h>
|
||||
|
||||
#define NINA_GPIO0 FPGA_NINA_GPIO0
|
||||
#define NINA_RESETN FPGA_SPIWIFI_RESET
|
||||
#endif
|
||||
|
||||
|
||||
#include "ESP32BootROM.h"
|
||||
|
||||
ESP32BootROMClass::ESP32BootROMClass(HardwareSerial& serial, int gpio0Pin, int resetnPin) :
|
||||
_serial(&serial),
|
||||
_gpio0Pin(gpio0Pin),
|
||||
_resetnPin(resetnPin)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::begin(unsigned long baudrate)
|
||||
{
|
||||
#ifdef ARDUINO_SAMD_MKRVIDOR4000
|
||||
FPGA.begin();
|
||||
|
||||
_serial->begin(119400);
|
||||
|
||||
FPGA.pinMode(_gpio0Pin, OUTPUT);
|
||||
FPGA.pinMode(_resetnPin, OUTPUT);
|
||||
|
||||
FPGA.digitalWrite(_gpio0Pin, LOW);
|
||||
|
||||
FPGA.digitalWrite(_resetnPin, LOW);
|
||||
delay(10);
|
||||
FPGA.digitalWrite(_resetnPin, HIGH);
|
||||
delay(100);
|
||||
|
||||
#elif defined(ARDUINO_AVR_UNO_WIFI_REV2)
|
||||
_serial->begin(119400);
|
||||
|
||||
pinMode(_gpio0Pin, OUTPUT);
|
||||
pinMode(_resetnPin, OUTPUT);
|
||||
|
||||
digitalWrite(_gpio0Pin, LOW);
|
||||
|
||||
digitalWrite(_resetnPin, LOW);
|
||||
delay(100);
|
||||
digitalWrite(_resetnPin, HIGH);
|
||||
delay(100);
|
||||
digitalWrite(_resetnPin, LOW);
|
||||
#else
|
||||
_serial->begin(115200);
|
||||
|
||||
pinMode(_gpio0Pin, OUTPUT);
|
||||
pinMode(_resetnPin, OUTPUT);
|
||||
|
||||
digitalWrite(_gpio0Pin, LOW);
|
||||
|
||||
digitalWrite(_resetnPin, HIGH);
|
||||
delay(10);
|
||||
digitalWrite(_resetnPin, LOW);
|
||||
delay(100);
|
||||
#if defined(ARDUINO_SAMD_NANO_33_IOT) ||defined(ARDUINO_NANO_RP2040_CONNECT)
|
||||
digitalWrite(_resetnPin, HIGH);
|
||||
delay(100);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int synced = 0;
|
||||
|
||||
for (int retries = 0; !synced && (retries < 5); retries++) {
|
||||
synced = sync();
|
||||
}
|
||||
|
||||
if (!synced) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(ARDUINO_SAMD_MKRVIDOR4000) || defined(ARDUINO_AVR_UNO_WIFI_REV2) || defined(ARDUINO_NANO_RP2040_CONNECT)
|
||||
(void)baudrate;
|
||||
#else
|
||||
if (baudrate != 115200) {
|
||||
if (!changeBaudrate(baudrate)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
delay(100);
|
||||
|
||||
_serial->end();
|
||||
_serial->begin(baudrate);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!spiAttach()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ESP32BootROMClass::end() {
|
||||
_serial->end();
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::sync()
|
||||
{
|
||||
const uint8_t data[] = {
|
||||
0x07, 0x07, 0x12, 0x20,
|
||||
0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55
|
||||
};
|
||||
|
||||
command(0x08, data, sizeof(data));
|
||||
|
||||
int results[8];
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
results[i] = response(0x08, 100);
|
||||
}
|
||||
|
||||
return (results[0] == 0);
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::changeBaudrate(unsigned long baudrate)
|
||||
{
|
||||
const uint32_t data[2] = {
|
||||
baudrate,
|
||||
0
|
||||
};
|
||||
|
||||
command(0x0f, data, sizeof(data));
|
||||
|
||||
return (response(0x0f, 3000) == 0);
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::spiAttach()
|
||||
{
|
||||
const uint8_t data[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
command(0x0d, data, sizeof(data));
|
||||
|
||||
return (response(0x0d, 3000) == 0);
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::beginFlash(uint32_t offset, uint32_t size, uint32_t chunkSize) {
|
||||
const uint32_t data[4] = {
|
||||
size,
|
||||
size / chunkSize,
|
||||
chunkSize,
|
||||
offset
|
||||
};
|
||||
|
||||
command(0x02, data, sizeof(data));
|
||||
|
||||
_flashSequenceNumber = 0;
|
||||
_chunkSize = chunkSize;
|
||||
|
||||
return (response(0x02, 120000) == 0);
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::dataFlash(const void* data, uint32_t length)
|
||||
{
|
||||
uint32_t cmdData[4 + (_chunkSize / 4)];
|
||||
|
||||
cmdData[0] = length;
|
||||
cmdData[1] = _flashSequenceNumber++;
|
||||
cmdData[2] = 0;
|
||||
cmdData[3] = 0;
|
||||
|
||||
memcpy(&cmdData[4], data, length);
|
||||
|
||||
if (length < _chunkSize) {
|
||||
memset(&cmdData[4 + (length / 4)], 0xff, _chunkSize - length);
|
||||
}
|
||||
|
||||
command(0x03, cmdData, sizeof(cmdData));
|
||||
|
||||
return (response(0x03, 3000) == 0);
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::endFlash(uint32_t reboot) {
|
||||
const uint32_t data[1] = {
|
||||
reboot
|
||||
};
|
||||
|
||||
command(0x04, data, sizeof(data));
|
||||
|
||||
return (response(0x04, 3000) == 0);
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::md5Flash(uint32_t offset, uint32_t size, uint8_t* result)
|
||||
{
|
||||
const uint32_t data[4] = {
|
||||
offset,
|
||||
size,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
command(0x13, data, sizeof(data));
|
||||
|
||||
uint8_t asciiResult[32];
|
||||
|
||||
if (response(0x13, 3000, asciiResult) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char temp[3] = { 0, 0, 0 };
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
temp[0] = asciiResult[i * 2];
|
||||
temp[1] = asciiResult[i * 2 + 1];
|
||||
|
||||
result[i] = strtoul(temp, NULL, 16);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ESP32BootROMClass::command(int opcode, const void* data, uint16_t length)
|
||||
{
|
||||
uint32_t checksum = 0;
|
||||
|
||||
if (opcode == 0x03) {
|
||||
checksum = 0xef; // seed
|
||||
|
||||
for (uint16_t i = 16; i < length; i++) {
|
||||
checksum ^= ((const uint8_t*)data)[i];
|
||||
}
|
||||
}
|
||||
|
||||
_serial->write(0xc0);
|
||||
_serial->write((uint8_t)0x00); // direction
|
||||
_serial->write(opcode);
|
||||
_serial->write((uint8_t*)&length, sizeof(length));
|
||||
writeEscapedBytes((uint8_t*)&checksum, sizeof(checksum));
|
||||
writeEscapedBytes((uint8_t*)data, length);
|
||||
_serial->write(0xc0);
|
||||
#ifdef ARDUINO_SAMD_MKRVIDOR4000
|
||||
// _serial->flush(); // doesn't work!
|
||||
#else
|
||||
_serial->flush();
|
||||
#endif
|
||||
}
|
||||
|
||||
int ESP32BootROMClass::response(int opcode, unsigned long timeout, void* body)
|
||||
{
|
||||
uint8_t data[10 + 256];
|
||||
uint16_t index = 0;
|
||||
|
||||
uint8_t responseLength = 4;
|
||||
|
||||
for (unsigned long start = millis(); (index < (uint16_t)(10 + responseLength)) && (millis() - start) < timeout;) {
|
||||
if (_serial->available()) {
|
||||
data[index] = _serial->read();
|
||||
|
||||
if (index == 3) {
|
||||
responseLength = data[index];
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (index) {
|
||||
for (int i = 0; i < index; i++) {
|
||||
byte b = data[i];
|
||||
|
||||
if (b < 0x10) {
|
||||
Serial.print('0');
|
||||
}
|
||||
|
||||
Serial.print(b, HEX);
|
||||
Serial.print(' ');
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (index != (uint16_t)(10 + responseLength)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (data[0] != 0xc0 || data[1] != 0x01 || data[2] != opcode || data[responseLength + 5] != 0x00 || data[responseLength + 6] != 0x00 || data[responseLength + 9] != 0xc0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (body) {
|
||||
memcpy(body, &data[9], responseLength - 4);
|
||||
}
|
||||
|
||||
return data[responseLength + 5];
|
||||
}
|
||||
|
||||
void ESP32BootROMClass::writeEscapedBytes(const uint8_t* data, uint16_t length)
|
||||
{
|
||||
uint16_t written = 0;
|
||||
|
||||
while (written < length) {
|
||||
uint8_t b = data[written++];
|
||||
|
||||
if (b == 0xdb) {
|
||||
_serial->write(0xdb);
|
||||
_serial->write(0xdd);
|
||||
} else if (b == 0xc0) {
|
||||
_serial->write(0xdb);
|
||||
_serial->write(0xdc);
|
||||
} else {
|
||||
_serial->write(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ESP32BootROMClass ESP32BootROM(SerialNina, NINA_GPIO0, NINA_RESETN);
|
||||
56
lib/WiFiNINA/examples/Tools/FirmwareUpdater/ESP32BootROM.h
Normal file
56
lib/WiFiNINA/examples/Tools/FirmwareUpdater/ESP32BootROM.h
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
ESP32BootROM - part of the Firmware Updater for the
|
||||
Arduino MKR WiFi 1010, Arduino MKR Vidor 4000, and Arduino UNO WiFi Rev.2.
|
||||
|
||||
Copyright (c) 2018 Arduino SA. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
class ESP32BootROMClass {
|
||||
public:
|
||||
ESP32BootROMClass(HardwareSerial& hwSerial, int gpio0Pin, int resetnPin);
|
||||
|
||||
int begin(unsigned long baudrate);
|
||||
void end();
|
||||
|
||||
int beginFlash(uint32_t offset, uint32_t size, uint32_t chunkSize);
|
||||
int dataFlash(const void* data, uint32_t length);
|
||||
int endFlash(uint32_t reboot);
|
||||
|
||||
int md5Flash(uint32_t offset, uint32_t size, uint8_t* result);
|
||||
|
||||
private:
|
||||
int sync();
|
||||
int changeBaudrate(unsigned long baudrate);
|
||||
int spiAttach();
|
||||
|
||||
void command(int opcode, const void* data, uint16_t length);
|
||||
int response(int opcode, unsigned long timeout, void* body = NULL);
|
||||
|
||||
void writeEscapedBytes(const uint8_t* data, uint16_t length);
|
||||
|
||||
private:
|
||||
HardwareSerial* _serial;
|
||||
int _gpio0Pin;
|
||||
int _resetnPin;
|
||||
|
||||
uint32_t _flashSequenceNumber;
|
||||
uint32_t _chunkSize;
|
||||
};
|
||||
|
||||
extern ESP32BootROMClass ESP32BootROM;
|
||||
60
lib/WiFiNINA/examples/Tools/FirmwareUpdater/Endianess.ino
Normal file
60
lib/WiFiNINA/examples/Tools/FirmwareUpdater/Endianess.ino
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Endianess.ino - Network byte order conversion functions.
|
||||
Copyright (c) 2015 Arduino LLC. All right reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
bool isBigEndian() {
|
||||
uint32_t test = 0x11223344;
|
||||
uint8_t *pTest = reinterpret_cast<uint8_t *>(&test);
|
||||
return pTest[0] == 0x11;
|
||||
}
|
||||
|
||||
uint32_t fromNetwork32(uint32_t from) {
|
||||
static const bool be = isBigEndian();
|
||||
if (be) {
|
||||
return from;
|
||||
} else {
|
||||
uint8_t *pFrom = reinterpret_cast<uint8_t *>(&from);
|
||||
uint32_t to;
|
||||
to = pFrom[0]; to <<= 8;
|
||||
to |= pFrom[1]; to <<= 8;
|
||||
to |= pFrom[2]; to <<= 8;
|
||||
to |= pFrom[3];
|
||||
return to;
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t fromNetwork16(uint16_t from) {
|
||||
static bool be = isBigEndian();
|
||||
if (be) {
|
||||
return from;
|
||||
} else {
|
||||
uint8_t *pFrom = reinterpret_cast<uint8_t *>(&from);
|
||||
uint16_t to;
|
||||
to = pFrom[0]; to <<= 8;
|
||||
to |= pFrom[1];
|
||||
return to;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t toNetwork32(uint32_t to) {
|
||||
return fromNetwork32(to);
|
||||
}
|
||||
|
||||
uint16_t toNetwork16(uint16_t to) {
|
||||
return fromNetwork16(to);
|
||||
}
|
||||
142
lib/WiFiNINA/examples/Tools/FirmwareUpdater/FirmwareUpdater.ino
Normal file
142
lib/WiFiNINA/examples/Tools/FirmwareUpdater/FirmwareUpdater.ino
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
FirmwareUpdater - Firmware Updater for the
|
||||
Arduino MKR WiFi 1010, Arduino MKR Vidor 4000, and Arduino UNO WiFi Rev.2.
|
||||
|
||||
Copyright (c) 2018 Arduino SA. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "ESP32BootROM.h"
|
||||
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
uint8_t command;
|
||||
uint32_t address;
|
||||
uint32_t arg1;
|
||||
uint16_t payloadLength;
|
||||
|
||||
// payloadLength bytes of data follows...
|
||||
} UartPacket;
|
||||
|
||||
static const int MAX_PAYLOAD_SIZE = 1024;
|
||||
|
||||
#define CMD_READ_FLASH 0x01
|
||||
#define CMD_WRITE_FLASH 0x02
|
||||
#define CMD_ERASE_FLASH 0x03
|
||||
#define CMD_MD5_FLASH 0x04
|
||||
#define CMD_MAX_PAYLOAD_SIZE 0x50
|
||||
#define CMD_HELLO 0x99
|
||||
|
||||
void setup() {
|
||||
Serial.begin(1000000);
|
||||
|
||||
if (!ESP32BootROM.begin(921600)) {
|
||||
Serial.println("Unable to communicate with ESP32 boot ROM!");
|
||||
while (1);
|
||||
}
|
||||
}
|
||||
|
||||
void receivePacket(UartPacket *pkt, uint8_t *payload) {
|
||||
// Read command
|
||||
uint8_t *p = reinterpret_cast<uint8_t *>(pkt);
|
||||
uint16_t l = sizeof(UartPacket);
|
||||
while (l > 0) {
|
||||
int c = Serial.read();
|
||||
if (c == -1)
|
||||
continue;
|
||||
*p++ = c;
|
||||
l--;
|
||||
}
|
||||
|
||||
// Convert parameters from network byte order to cpu byte order
|
||||
pkt->address = fromNetwork32(pkt->address);
|
||||
pkt->arg1 = fromNetwork32(pkt->arg1);
|
||||
pkt->payloadLength = fromNetwork16(pkt->payloadLength);
|
||||
|
||||
// Read payload
|
||||
l = pkt->payloadLength;
|
||||
while (l > 0) {
|
||||
int c = Serial.read();
|
||||
if (c == -1)
|
||||
continue;
|
||||
*payload++ = c;
|
||||
l--;
|
||||
}
|
||||
}
|
||||
|
||||
// Allocated statically so the compiler can tell us
|
||||
// about the amount of used RAM
|
||||
static UartPacket pkt;
|
||||
static uint8_t payload[MAX_PAYLOAD_SIZE];
|
||||
|
||||
void loop() {
|
||||
receivePacket(&pkt, payload);
|
||||
|
||||
if (pkt.command == CMD_HELLO) {
|
||||
if (pkt.address == 0x11223344 && pkt.arg1 == 0x55667788)
|
||||
Serial.print("v10000");
|
||||
}
|
||||
|
||||
if (pkt.command == CMD_MAX_PAYLOAD_SIZE) {
|
||||
uint16_t res = toNetwork16(MAX_PAYLOAD_SIZE);
|
||||
Serial.write(reinterpret_cast<uint8_t *>(&res), sizeof(res));
|
||||
}
|
||||
|
||||
if (pkt.command == CMD_READ_FLASH) {
|
||||
// not supported!
|
||||
Serial.println("ER");
|
||||
}
|
||||
|
||||
if (pkt.command == CMD_WRITE_FLASH) {
|
||||
uint32_t len = pkt.payloadLength;
|
||||
if (!ESP32BootROM.dataFlash(payload, len)) {
|
||||
Serial.print("ER");
|
||||
} else {
|
||||
Serial.print("OK");
|
||||
}
|
||||
}
|
||||
|
||||
if (pkt.command == CMD_ERASE_FLASH) {
|
||||
uint32_t address = pkt.address;
|
||||
uint32_t len = pkt.arg1;
|
||||
if (!ESP32BootROM.beginFlash(address, len, MAX_PAYLOAD_SIZE)) {
|
||||
Serial.print("ER");
|
||||
} else {
|
||||
Serial.print("OK");
|
||||
}
|
||||
}
|
||||
|
||||
if (pkt.command == CMD_MD5_FLASH) {
|
||||
uint32_t address = pkt.address;
|
||||
uint32_t len = pkt.arg1;
|
||||
|
||||
if (!ESP32BootROM.endFlash(1)) {
|
||||
Serial.print("ER");
|
||||
} else {
|
||||
ESP32BootROM.end();
|
||||
|
||||
uint8_t md5[16];
|
||||
|
||||
if (!ESP32BootROM.begin(921600)) {
|
||||
Serial.print("ER");
|
||||
} else if (!ESP32BootROM.md5Flash(address, len, md5)) {
|
||||
Serial.print("ER");
|
||||
} else {
|
||||
Serial.print("OK");
|
||||
Serial.write(md5, sizeof(md5));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user