diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 2d1d4f6ca..9396c53fd 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -237,7 +237,8 @@ "ringbuffer", "system", "leds", - "hw" + "hw", + "bootloader" ] }, { diff --git a/src/Makefile b/src/Makefile index d4aa2a590..174628ff7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -229,7 +229,6 @@ endif @$(BUILD_DIR_BASE)/sysexgen/$(TARGET)/$(BUILD_TYPE)/$(TARGET).elf $(BUILD_DIR)/$(TARGET)$(SYSEX_BINARY_SUFFIX).bin $(BUILD_DIR)/$(TARGET).sysex.syx #ascii sysex file for use with web configurator @hexdump -v -e '/1 "%02x "' $(BUILD_DIR)/$(TARGET).sysex.syx | sed 's/f7/f7\n/g' | sed 's/^ *//' | tr a-z A-Z > $(BUILD_DIR)/$(TARGET).sysex - @rm $(BUILD_DIR)/$(TARGET)$(SYSEX_BINARY_SUFFIX).bin @echo SysEx file created: $(BUILD_DIR)/$(TARGET).sysex pre-build: $(PINS_GEN_SOURCE) $(TSCREEN_GEN_SOURCE) diff --git a/tests/Sources.mk b/tests/Sources.mk index 40c55ff61..1a808d47e 100644 --- a/tests/Sources.mk +++ b/tests/Sources.mk @@ -22,7 +22,9 @@ modules/u8g2/csrc/u8x8_gpio.c \ modules/u8g2/csrc/u8x8_d_ssd1306_128x64_noname.c \ modules/u8g2/csrc/u8x8_d_ssd1306_128x32.c -ifeq ($(ARCH),stm32) +ifeq ($(ARCH), avr) + SOURCES_COMMON += board/$(ARCH)/common/FlashPages.cpp +else SOURCES_COMMON += $(MCU_DIR)/FlashPages.cpp endif @@ -30,6 +32,10 @@ endif INCLUDE_DIRS_COMMON := \ -I"./" \ -I"./unity" \ --I"../src/application/" \ +-I"../modules/" \ -I"../src/" \ --I"../modules/" +-I"../src/bootloader/" \ +-I"../src/application/" \ +-I"../src/board/$(ARCH)/variants/$(MCU_FAMILY)" \ +-I"../src/$(MCU_DIR)" \ +-I"../src/$(BOARD_TARGET_DIR)/" diff --git a/tests/src/bootloader/Makefile b/tests/src/bootloader/Makefile new file mode 100644 index 000000000..707daa037 --- /dev/null +++ b/tests/src/bootloader/Makefile @@ -0,0 +1,7 @@ +vpath application/%.cpp ../src +vpath bootloader/%.cpp ../src +vpath common/%.cpp ../src + +SOURCES_$(shell basename $(dir $(lastword $(MAKEFILE_LIST)))) := \ +bootloader/SysExParser/SysExParser.cpp \ +bootloader/updater/Updater.cpp \ No newline at end of file diff --git a/tests/src/bootloader/test.cpp b/tests/src/bootloader/test.cpp new file mode 100644 index 000000000..59e49c9e2 --- /dev/null +++ b/tests/src/bootloader/test.cpp @@ -0,0 +1,159 @@ +#include "unity/Framework.h" +#include "SysExParser/SysExParser.h" +#include "updater/Updater.h" +#include "board/Board.h" +#include "board/Internal.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace +{ + class BTLDRWriter : public Updater::BTLDRWriter + { + public: + uint32_t pageSize(size_t index) override + { + return Board::detail::map::flashPageDescriptor(index).size; + } + + void erasePage(size_t index) override + { + } + + void fillPage(size_t index, uint32_t address, uint16_t data) override + { + writtenBytes.push_back(data & 0xFF); + writtenBytes.push_back(data >> 8); + } + + void writePage(size_t index) override + { + } + + void apply() override + { + updated = true; + } + + std::vector writtenBytes = {}; + bool updated = false; + }; + + const std::string fw_build_dir = "../src/build/merged/"; + const std::string fw_build_type_subdir = "release/"; + + SysExParser _sysExParser; + BTLDRWriter _btldrWriter; + Updater _updater = Updater(_btldrWriter, COMMAND_FW_UPDATE_START, COMMAND_FW_UPDATE_END, FW_UID); + + void sysExToUSBMidi(std::vector sysex, std::vector& packets) + { + class MIDIHWA : public MIDI::HWA + { + public: + MIDIHWA(std::vector& packets) + : _packets(packets) + {} + + bool init() override + { + return true; + } + + bool dinRead(uint8_t& data) override + { + return false; + } + + bool dinWrite(uint8_t data) override + { + return false; + } + + bool usbRead(MIDI::USBMIDIpacket_t& USBMIDIpacket) override + { + return false; + } + + bool usbWrite(MIDI::USBMIDIpacket_t& USBMIDIpacket) override + { + _packets.push_back(USBMIDIpacket); + return true; + } + + private: + std::vector& _packets; + }; + + MIDIHWA midiHWA(packets); + MIDI midi(midiHWA); + + midi.init(); + midi.enableUSBMIDI(); + + midi.sendSysEx(sysex.size(), &sysex[0], true); + } + +} // namespace + +TEST_CASE(Bootloader) +{ + std::string syxPath = fw_build_dir + BOARD_STRING + "/" + fw_build_type_subdir + BOARD_STRING + ".sysex.syx"; + std::string binaryPath = fw_build_dir + BOARD_STRING + "/" + fw_build_type_subdir + BOARD_STRING + "_sysex.bin"; + + std::ifstream sysExStream(syxPath, std::ios::in | std::ios::binary); + std::vector sysExVector((std::istreambuf_iterator(sysExStream)), std::istreambuf_iterator()); + std::ifstream binaryStream(binaryPath, std::ios::in | std::ios::binary); + std::vector binaryVector((std::istreambuf_iterator(binaryStream)), std::istreambuf_iterator()); + + std::vector singleSysExMsg = {}; + std::vector packets = {}; + + //go over the entire .sysex file + //upon reaching the end of single sysex message, convert it + //into series of USB MIDI packets + for (size_t i = 0; i < sysExVector.size(); i++) + { + singleSysExMsg.push_back(sysExVector.at(i)); + + if (sysExVector.at(i) == 0xF7) + { + sysExToUSBMidi(singleSysExMsg, packets); + singleSysExMsg.clear(); + } + } + + //now we have the entire file in form of USB MIDI packets + //parse each message and once parsing passes, feed the parsed data into fw updater + for (size_t packet = 0; packet < packets.size(); packet++) + { + if (_sysExParser.isValidMessage(packets.at(packet))) + { + size_t dataSize = _sysExParser.dataBytes(); + uint8_t data = 0; + + if (dataSize) + { + for (size_t i = 0; i < dataSize; i++) + { + if (_sysExParser.value(i, data)) + { + _updater.feed(data); + } + } + } + } + } + + //once all data has been fed into updater, firmware update procedure should be complete + TEST_ASSERT(_btldrWriter.updated == true); + + //written content should also match the original binary file from which .syx file has been created + TEST_ASSERT(_btldrWriter.writtenBytes == binaryVector); +} \ No newline at end of file