diff --git a/Makefile b/Makefile index c95a171b..6095f868 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ WXVERSION=3.0 # # Source files # -COMMON_SRCS=Samba.cpp Flash.cpp D5xNvmFlash.cpp D2xNvmFlash.cpp EfcFlash.cpp EefcFlash.cpp Applet.cpp WordCopyApplet.cpp Flasher.cpp Device.cpp +COMMON_SRCS=Samba.cpp Flash.cpp D5xNvmFlash.cpp D2xNvmFlash.cpp NullFlash.cpp EfcFlash.cpp EefcFlash.cpp Applet.cpp WordCopyApplet.cpp Flasher.cpp Device.cpp APPLET_SRCS=WordCopyArm.asm BOSSA_SRCS=BossaForm.cpp BossaWindow.cpp BossaAbout.cpp BossaApp.cpp BossaBitmaps.cpp BossaInfo.cpp BossaThread.cpp BossaProgress.cpp BOSSA_BMPS=BossaLogo.bmp BossaIcon.bmp ShumaTechLogo.bmp @@ -28,7 +28,7 @@ INSTALLDIR=install # # Determine OS # -OS:=$(shell uname -s | cut -c -7) +OS?=$(shell uname -s | cut -c -7) # # Windows rules @@ -39,7 +39,7 @@ WXVERSION=3.1 EXE=.exe COMMON_SRCS+=WinSerialPort.cpp WinPortFactory.cpp COMMON_LDFLAGS=-Wl,--enable-auto-import -static -static-libstdc++ -static-libgcc -COMMON_LIBS=-ltermcap -Wl,--as-needed -lsetupapi +COMMON_LIBS=-Wl,--as-needed -lsetupapi BOSSA_RC=BossaRes.rc WIXDIR="C:\Program Files (x86)\WiX Toolset v3.11\bin" CODE_SIGN=$(INSTALLDIR)\\code_sign.p12 diff --git a/src/D2xNvmFlash.cpp b/src/D2xNvmFlash.cpp index 0974936c..aaaaf101 100644 --- a/src/D2xNvmFlash.cpp +++ b/src/D2xNvmFlash.cpp @@ -107,6 +107,10 @@ D2xNvmFlash::erase(uint32_t offset, uint32_t size) void D2xNvmFlash::eraseAll(uint32_t offset) { + if (offset == 0) { + // Not bailing out will provoke the bootloader to be erased + throw FlashEraseError(); + } // Use the extended Samba command if available if (_samba.canChipErase()) { diff --git a/src/Device.cpp b/src/Device.cpp index 0c94ae44..dd312aad 100644 --- a/src/Device.cpp +++ b/src/Device.cpp @@ -31,6 +31,7 @@ #include "EefcFlash.h" #include "D2xNvmFlash.h" #include "D5xNvmFlash.h" +#include "NullFlash.h" void Device::readChipId(uint32_t& chipId, uint32_t& extChipId) @@ -49,14 +50,30 @@ void Device::create() { Flash* flashPtr; + + // If the bootloader supports automatic chip identification... + if (_samba.canIdentifyChip()) { + std::string id = _samba.identifyChip(); + + if (id == "nRF52840-QIAA") { + _family = FAMILY_NRF52; + flashPtr = new NullFlash(_samba, "nRF52840-QIAA", 256, 4096, 0x00000000, 0x00000000); + } else { + throw DeviceUnsupportedError(); + } + + _flash = std::unique_ptr(flashPtr); + return; + } + + // Device identification must be performed carefully to avoid reading from + // addresses that devices do not support which will lock up the CPU + uint32_t chipId = 0; uint32_t cpuId = 0; uint32_t extChipId = 0; uint32_t deviceId = 0; - // Device identification must be performed carefully to avoid reading from - // addresses that devices do not support which will lock up the CPU - // All devices support addresss 0 as the ARM reset vector so if the vector is // a ARM7TDMI branch, then assume we have an Atmel SAM7/9 CHIPID register if ((_samba.readWord(0x0) & 0xff000000) == 0xea000000) @@ -636,6 +653,11 @@ Device::reset() { try { + if (_samba.canReset()) { + _samba.reset(); + return; + } + switch (_family) { case FAMILY_SAMD21: diff --git a/src/Device.h b/src/Device.h index 5475c557..89654b4e 100644 --- a/src/Device.h +++ b/src/Device.h @@ -77,6 +77,8 @@ class Device FAMILY_SAMS70, FAMILY_SAMV70, FAMILY_SAMV71, + + FAMILY_NRF52, }; Device(Samba& samba) : _samba(samba), _flash(nullptr), _family(FAMILY_NONE) {} diff --git a/src/Flasher.cpp b/src/Flasher.cpp index 7591cf9f..96326461 100644 --- a/src/Flasher.cpp +++ b/src/Flasher.cpp @@ -208,6 +208,8 @@ Flasher::verify(const char* filename, uint32_t& pageErrors, uint32_t& totalError if (_samba.canChecksumBuffer()) { + calcCrc = 0; + for (uint32_t i = 0; i < fbytes; i++) calcCrc = _samba.checksumCalc(bufferA[i], calcCrc); diff --git a/src/NullFlash.cpp b/src/NullFlash.cpp new file mode 100644 index 00000000..cd1d776d --- /dev/null +++ b/src/NullFlash.cpp @@ -0,0 +1,127 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2018, ShumaTech +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +/////////////////////////////////////////////////////////////////////////////// + +#include "NullFlash.h" + +NullFlash::NullFlash( + Samba& samba, + const std::string& name, + uint32_t pages, + uint32_t size, + uint32_t user, + uint32_t stack) + : + Flash(samba, name, 0, pages, size, 1, 0, user, stack) +{ +} + +NullFlash::~NullFlash() +{ +} + +void +NullFlash::erase(uint32_t offset, uint32_t size) +{ + throw FlashEraseError(); +} + +void +NullFlash::eraseAll(uint32_t offset) +{ + // Use the extended Samba command if available + if (_samba.canChipErase()) + { + _samba.chipErase(offset); + } + else + { + erase(offset, totalSize() - offset); + } +} + +void +NullFlash::eraseAuto(bool enable) +{ + _eraseAuto = enable; +} + +std::vector +NullFlash::getLockRegions() +{ + std::vector regions(0); + return regions; +} + +bool +NullFlash::getSecurity() +{ + return false; +} + +bool +NullFlash::getBod() +{ + return false; +} + +bool +NullFlash::getBor() +{ + return false; +} + +bool +NullFlash::getBootFlash() +{ + return true; +} + +void +NullFlash::writeOptions() +{ + return; +} + +void +NullFlash::writePage(uint32_t page) +{ + throw FlashPageError(); +} + +void +NullFlash::readPage(uint32_t page, uint8_t* buf) +{ + if (page >= _pages) + { + throw FlashPageError(); + } + + _samba.read(_addr + (page * _size), buf, _size); +} + +void +NullFlash::writeBuffer(uint32_t dst_addr, uint32_t size) +{ + // Auto-erase if enabled + if (_eraseAuto) + erase(dst_addr, size); + + // Call the base class method + Flash::writeBuffer(dst_addr, size); +} diff --git a/src/NullFlash.h b/src/NullFlash.h new file mode 100644 index 00000000..7616c581 --- /dev/null +++ b/src/NullFlash.h @@ -0,0 +1,69 @@ +/////////////////////////////////////////////////////////////////////////////// +// BOSSA +// +// Copyright (c) 2018, ShumaTech +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _NULLFLASH_H +#define _NULLFLASH_H + +#include +#include + +#include "Flash.h" + +class NullFlash : public Flash +{ +public: + NullFlash( + Samba& samba, + const std::string& name, + uint32_t pages, + uint32_t size, + uint32_t user, + uint32_t stack); + + virtual ~NullFlash(); + + void eraseAll(uint32_t offset); + void eraseAuto(bool enable); + + std::vector getLockRegions(); + + bool getSecurity(); + + bool getBod(); + bool canBod() { return false; } + + bool getBor(); + bool canBor() { return false; } + + bool getBootFlash(); + bool canBootFlash() { return false; } + + void writeOptions(); + + void writePage(uint32_t page); + void readPage(uint32_t page, uint8_t* data); + + void writeBuffer(uint32_t dst_addr, uint32_t size); + +protected: + bool _eraseAuto; + void erase(uint32_t offset, uint32_t size); +}; + +#endif // _NULLFLASH_H diff --git a/src/PosixSerialPort.cpp b/src/PosixSerialPort.cpp index 45eaca9c..4ca79549 100644 --- a/src/PosixSerialPort.cpp +++ b/src/PosixSerialPort.cpp @@ -257,7 +257,13 @@ PosixSerialPort::write(const uint8_t* buffer, int len) if (_devfd == -1) return -1; - int res = ::write(_devfd, buffer, len); + int res; + + do { + res = ::write(_devfd, buffer, len); + } while (res == -1 && errno == EAGAIN); + + // Used on macos to avoid upload errors if (_autoFlush) flush(); @@ -290,10 +296,7 @@ PosixSerialPort::put(int c) void PosixSerialPort::flush() { - // There isn't a reliable way to flush on a file descriptor - // so we just wait it out. One millisecond is the USB poll - // interval so that should cover it. - usleep(1000); + fsync(_devfd); } bool diff --git a/src/Samba.cpp b/src/Samba.cpp index 490e3936..bd6ee23a 100644 --- a/src/Samba.cpp +++ b/src/Samba.cpp @@ -58,6 +58,8 @@ Samba::Samba() : _canChipErase(false), _canWriteBuffer(false), _canChecksumBuffer(false), + _canIdentifyChip(false), + _canReset(false), _readBufferSize(0), _debug(false), _isUsb(false) @@ -119,6 +121,8 @@ Samba::init() { switch (ver[extIndex]) { + case 'I': _canIdentifyChip = true; break; + case 'K': _canReset = true; break; case 'X': _canChipErase = true; break; case 'Y': _canWriteBuffer = true; break; case 'Z': _canChecksumBuffer = true; break; @@ -147,7 +151,7 @@ Samba::connect(SerialPort::Ptr port, int bps) _isUsb = _port->isUsb(); if (_isUsb) { - if (_port->open(921600) && init()) + if (_port->open(230400) && init()) { if (_debug) printf("Connected at 921600 baud\n"); @@ -199,6 +203,8 @@ Samba::writeByte(uint32_t addr, uint8_t value) // port object's flush method before writing the data. if (_isUsb) _port->flush(); + + usleep(10000); } uint8_t @@ -242,6 +248,8 @@ Samba::writeWord(uint32_t addr, uint32_t value) // port object's flush method before writing the data. if (_isUsb) _port->flush(); + + usleep(10000); } @@ -455,6 +463,7 @@ Samba::writeBinary(const uint8_t* buffer, int size) buffer += written; size -= written; } + usleep(10000); } void @@ -582,6 +591,40 @@ Samba::version() return ver; } +std::string +Samba::identifyChip() +{ + uint8_t cmd[256]; + char* str; + int size; + int pos; + + cmd[0] = 'I'; + cmd[1] = '#'; + _port->write(cmd, 2); + + _port->timeout(TIMEOUT_QUICK); + size = _port->read(cmd, sizeof(cmd) - 1); + _port->timeout(TIMEOUT_NORMAL); + if (size <= 0) + throw SambaError(); + + str = (char*) cmd; + for (pos = 0; pos < size; pos++) + { + if (!isprint(str[pos])) + break; + } + str[pos] = '\0'; + + std::string ver(str); + + if (_debug) + printf("%s()=%s\n", __FUNCTION__, ver.c_str()); + + return ver; +} + void Samba::chipErase(uint32_t start_addr) { @@ -619,7 +662,7 @@ Samba::writeBuffer(uint32_t src_addr, uint32_t dst_addr, uint32_t size) int l = snprintf((char*) cmd, sizeof(cmd), "Y%08X,0#", src_addr); if (_port->write(cmd, l) != l) throw SambaError(); - _port->timeout(TIMEOUT_QUICK); + _port->timeout(TIMEOUT_NORMAL); cmd[0] = 0; _port->read(cmd, 3); // Expects "Y\n\r" _port->timeout(TIMEOUT_NORMAL); @@ -670,3 +713,18 @@ Samba::checksumBuffer(uint32_t start_addr, uint32_t size) return res; } +void +Samba::reset() +{ + if (!_canReset) + throw SambaError(); + + if (_debug) + printf("%s()\n", __FUNCTION__); + + uint8_t cmd[2]; + cmd[0] = 'K'; + cmd[1] = '#'; + if (_port->write(cmd, 2) != 2) + throw SambaError(); +} diff --git a/src/Samba.h b/src/Samba.h index 84bea406..7d35c3ad 100644 --- a/src/Samba.h +++ b/src/Samba.h @@ -74,8 +74,6 @@ class Samba const SerialPort& getSerialPort() { return *_port; } - void reset(); - // Extended SAM-BA functions bool canChipErase() { return _canChipErase; } void chipErase(uint32_t start_addr); @@ -89,10 +87,18 @@ class Samba uint32_t checksumBufferSize() { return 4096; } uint16_t checksumCalc(uint8_t c, uint16_t crc); + bool canIdentifyChip() { return _canIdentifyChip; } + std::string identifyChip(); + + bool canReset() { return _canReset; } + void reset(); + private: bool _canChipErase; bool _canWriteBuffer; bool _canChecksumBuffer; + bool _canIdentifyChip; + bool _canReset; int _readBufferSize; bool _debug; bool _isUsb;