lib: Add bossac 1.9 code to lib directory
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
This commit is contained in:
parent
79632878ac
commit
2b9124f3c0
|
@ -50,6 +50,10 @@ The hub-ctrl directory contains code from:
|
|||
https://github.com/codazoda/hub-ctrl.c/
|
||||
revision 42095e522859059e8a5f4ec05c1e3def01a870a9.
|
||||
|
||||
The bossac directory contains code from:
|
||||
https://github.com/shumatech/BOSSA
|
||||
version 1.9 (b176eeef918fc810045c832348590595120187b4).
|
||||
|
||||
The pru_rpmsg directory contains code from:
|
||||
https://github.com/dinuxbg/pru-gcc-examples
|
||||
revision 425a42d82006cf0aa24be27b483d2f6a41607489. The code is taken
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
Copyright (c) 2011-2016, ShumaTech
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the <organization> nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -0,0 +1,347 @@
|
|||
.DEFAULT_GOAL := all
|
||||
|
||||
#
|
||||
# Version
|
||||
#
|
||||
VERSION=1.9
|
||||
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
|
||||
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
|
||||
BOSSAC_SRCS=bossac.cpp CmdOpts.cpp
|
||||
BOSSASH_SRCS=bossash.cpp Shell.cpp Command.cpp
|
||||
|
||||
#
|
||||
# Build directories
|
||||
#
|
||||
BINDIR=bin
|
||||
OBJDIR=obj
|
||||
SRCDIR=src
|
||||
RESDIR=res
|
||||
INSTALLDIR=install
|
||||
|
||||
#
|
||||
# Determine OS
|
||||
#
|
||||
OS:=$(shell uname -s | cut -c -7)
|
||||
|
||||
#
|
||||
# Windows rules
|
||||
#
|
||||
ifeq ($(OS),MINGW32)
|
||||
# Use wxWindows development branch to work around font scaling issues on Windows
|
||||
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
|
||||
BOSSA_RC=BossaRes.rc
|
||||
WIXDIR="C:\Program Files (x86)\WiX Toolset v3.10\bin"
|
||||
CODE_SIGN=$(INSTALLDIR)\\code_sign.p12
|
||||
TIMESTAMP=http://timestamp.comodoca.com/authenticode
|
||||
SIGNTOOL="C:\Program Files (x86)\Windows Kits\10\bin\x64\signtool.exe"
|
||||
INF2CAT="C:\Program Files (x86)\Windows Kits\10\bin\x86\Inf2Cat.exe"
|
||||
|
||||
define bossa_msi
|
||||
$(OBJDIR)\\bossa-$(1)-$(VERSION).wixobj: $(INSTALLDIR)\\bossa.wxs
|
||||
$(WIXDIR)\\candle.exe -dVersion=$(VERSION) -arch $(1) -out $$@ -ext $(WIXDIR)\\WixUIExtension.dll -ext $(WIXDIR)\\WixDifxAppExtension.dll $$<
|
||||
|
||||
$(BINDIR)\\bossa-$(1)-$(VERSION).msi: $(OBJDIR)\\bossa-$(1)-$(VERSION).wixobj
|
||||
$(WIXDIR)\\light.exe -cultures:null -out $$@ -pdbout $(OBJDIR)\\bossa.wixpdb -sice:ICE57 -ext $(WIXDIR)\\WixUIExtension.dll -ext $(WIXDIR)\\WixDifxAppExtension.dll $(WIXDIR)\\difxapp_$(1).wixlib $$<
|
||||
$$(Q)read -p "Password:" -rs PASSWORD; \
|
||||
cmd /C '$(SIGNTOOL) sign /v /fd sha256 /f $(CODE_SIGN) -t $(TIMESTAMP) /p '$$$$PASSWORD' $$@'
|
||||
endef
|
||||
|
||||
$(eval $(call bossa_msi,x86))
|
||||
$(eval $(call bossa_msi,x64))
|
||||
|
||||
$(INSTALLDIR)\\bossa.cat: $(INSTALLDIR)\\bossa.inf
|
||||
export TMP=$$(mktemp -d); \
|
||||
cp $< $$TMP; \
|
||||
cmd /C '$(INF2CAT) /v /driver:'$$(cygpath -w $$TMP)' /os:XP_X86,Vista_X86,Vista_X64,7_X86,7_X64,8_X86,8_X64,6_3_X86,6_3_X64,10_x86,10_x64'; \
|
||||
mv $$TMP/bossa.cat $@; \
|
||||
rm -rf $$TMP; \
|
||||
read -p "Password:" -rs PASSWORD; \
|
||||
cmd /C '$(SIGNTOOL) sign /v /fd sha256 /f $(CODE_SIGN) -t $(TIMESTAMP) /p '$$PASSWORD' $@'
|
||||
|
||||
bossa.cat: $(INSTALLDIR)\\bossa.cat
|
||||
|
||||
install32: $(BINDIR)\\bossa-x86-$(VERSION).msi
|
||||
install64: $(BINDIR)\\bossa-x64-$(VERSION).msi
|
||||
.PHONY: install
|
||||
install: strip install32 install64
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
# Linux rules
|
||||
#
|
||||
ifeq ($(OS),Linux)
|
||||
COMMON_SRCS+=PosixSerialPort.cpp LinuxPortFactory.cpp
|
||||
COMMON_LIBS=-Wl,--as-needed
|
||||
COMMON_CXXFLAGS=-std=c++11
|
||||
WX_LIBS+=-lX11
|
||||
|
||||
MACHINE:=$(shell uname -m)
|
||||
|
||||
install: strip
|
||||
tar cvzf $(BINDIR)/bossa-$(MACHINE)-$(VERSION).tgz -C $(BINDIR) bossa$(EXE) bossac$(EXE) bossash$(EXE)
|
||||
endif
|
||||
|
||||
#
|
||||
# OS X rules
|
||||
#
|
||||
ifeq ($(OS),Darwin)
|
||||
COMMON_SRCS+=PosixSerialPort.cpp OSXPortFactory.cpp
|
||||
COMMON_CXXFLAGS=-arch x86_64 -mmacosx-version-min=10.9
|
||||
COMMON_LDFLAGS=-arch x86_64 -mmacosx-version-min=10.9
|
||||
APP=BOSSA.app
|
||||
DMG=bossa-$(VERSION).dmg
|
||||
VOLUME=BOSSA
|
||||
BACKGROUND=$(INSTALLDIR)/background.png
|
||||
.PHONY: install
|
||||
app:
|
||||
mkdir -p $(BINDIR)/$(APP)/Contents/MacOS
|
||||
mkdir -p $(BINDIR)/$(APP)/Contents/Resources
|
||||
cp -f $(INSTALLDIR)/Info.plist $(BINDIR)/$(APP)/Contents
|
||||
echo -n "APPL????" > $(BINDIR)/$(APP)/Contents/PkgInfo
|
||||
ln -f $(BINDIR)/bossa $(BINDIR)/$(APP)/Contents/MacOS/bossa
|
||||
cp -f $(RESDIR)/BossaIcon.icns $(BINDIR)/$(APP)/Contents/Resources
|
||||
install: strip app
|
||||
hdiutil create -ov -megabytes 5 -fs HFS+ -volname $(VOLUME) $(BINDIR)/$(DMG)
|
||||
hdiutil attach -noautoopen $(BINDIR)/$(DMG)
|
||||
cp -R $(BINDIR)/$(APP) /Volumes/$(VOLUME)/
|
||||
cp $(BINDIR)/bossac$(EXE) /Volumes/$(VOLUME)/
|
||||
cp $(BINDIR)/bossash$(EXE) /Volumes/$(VOLUME)/
|
||||
ln -s /Applications /Volumes/$(VOLUME)/Applications
|
||||
ln -s /usr/local/bin /Volumes/$(VOLUME)/bin
|
||||
mkdir /Volumes/$(VOLUME)/.background
|
||||
cp $(BACKGROUND) /Volumes/$(VOLUME)/.background
|
||||
osascript < $(INSTALLDIR)/dmgwin.osa
|
||||
hdiutil detach /Volumes/$(VOLUME)/
|
||||
hdiutil convert -format UDBZ -o $(BINDIR)/tmp$(DMG) $(BINDIR)/$(DMG)
|
||||
mv -f $(BINDIR)/tmp$(DMG) $(BINDIR)/$(DMG)
|
||||
endif
|
||||
|
||||
#
|
||||
# OpenBSD rules
|
||||
# (This is likely to work without changes, but not tested, on other BSDs)
|
||||
#
|
||||
ifeq ($(OS),OpenBSD)
|
||||
|
||||
COMMON_SRCS+=PosixSerialPort.cpp BSDPortFactory.cpp
|
||||
|
||||
# This is only needed for bossash, but we can't add it to BOSSASH_LIBS here
|
||||
# because that one is redefined later.
|
||||
COMMON_LIBS+=-ltermcap
|
||||
|
||||
# As of 5.7, OpenBSD packages WxWidgets 2.8
|
||||
# bossa builds, runs, and appears to play nicely with this version,
|
||||
# but fails to do anything useful on systems that don't have hardware
|
||||
# serial ports because of USB detection problems.
|
||||
# (The SAM's USB programming port doesn't get recognized as a ucom
|
||||
# device, and a USB serial adaptor attached to the UART gets detected
|
||||
# by bossa as a USB interface and doesn't fall back to the serial
|
||||
# programming protocol.)
|
||||
WXVERSION=2.8
|
||||
|
||||
endif
|
||||
|
||||
ifeq (${OS},FreeBSD)
|
||||
|
||||
# This is only needed for bossash, but we can't add it to BOSSASH_LIBS here
|
||||
# because that one is redefined later.
|
||||
COMMON_SRCS+=PosixSerialPort.cpp BSDPortFactory.cpp
|
||||
|
||||
endif
|
||||
|
||||
#
|
||||
# Object files
|
||||
#
|
||||
COMMON_OBJS=$(foreach src,$(COMMON_SRCS),$(OBJDIR)/$(src:%.cpp=%.o))
|
||||
APPLET_OBJS=$(foreach src,$(APPLET_SRCS),$(OBJDIR)/$(src:%.asm=%.o))
|
||||
BOSSA_OBJS=$(APPLET_OBJS) $(COMMON_OBJS) $(foreach src,$(BOSSA_SRCS),$(OBJDIR)/$(src:%.cpp=%.o))
|
||||
ifdef BOSSA_RC
|
||||
BOSSA_OBJS+=$(OBJDIR)/$(BOSSA_RC:%.rc=%.o)
|
||||
endif
|
||||
BOSSAC_OBJS=$(APPLET_OBJS) $(COMMON_OBJS) $(foreach src,$(BOSSAC_SRCS),$(OBJDIR)/$(src:%.cpp=%.o))
|
||||
BOSSASH_OBJS=$(APPLET_OBJS) $(COMMON_OBJS) $(foreach src,$(BOSSASH_SRCS),$(OBJDIR)/$(src:%.cpp=%.o))
|
||||
|
||||
#
|
||||
# Dependencies
|
||||
#
|
||||
DEPENDS=$(COMMON_SRCS:%.cpp=$(OBJDIR)/%.d)
|
||||
DEPENDS+=$(APPLET_SRCS:%.asm=$(OBJDIR)/%.d)
|
||||
DEPENDS+=$(BOSSA_SRCS:%.cpp=$(OBJDIR)/%.d)
|
||||
DEPENDS+=$(BOSSAC_SRCS:%.cpp=$(OBJDIR)/%.d)
|
||||
DEPENDS+=$(BOSSASH_SRCS:%.cpp=$(OBJDIR)/%.d)
|
||||
|
||||
#
|
||||
# Tools
|
||||
#
|
||||
Q?=@
|
||||
CXX?=g++
|
||||
ARM=arm-none-eabi-
|
||||
ARMAS=$(ARM)as
|
||||
ARMOBJCOPY=$(ARM)objcopy
|
||||
|
||||
#
|
||||
# CXX Flags
|
||||
#
|
||||
# COMMON_CXXFLAGS+=-Wall -Werror -MT $@ -MD -MP -MF $(@:%.o=%.d) -DVERSION=\"$(VERSION)\" -g -O2
|
||||
COMMON_CXXFLAGS+=-Wall -MT $@ -MD -MP -MF $(@:%.o=%.d) -DVERSION=\"$(VERSION)\" -g -O2 $(CXXFLAGS)
|
||||
WX_CXXFLAGS:=$(shell wx-config --cxxflags --version=$(WXVERSION)) -DWX_PRECOMP -Wno-ctor-dtor-privacy -O2 -fno-strict-aliasing
|
||||
BOSSA_CXXFLAGS=$(COMMON_CXXFLAGS) $(WX_CXXFLAGS)
|
||||
BOSSAC_CXXFLAGS=$(COMMON_CXXFLAGS)
|
||||
BOSSASH_CXXFLAGS=$(COMMON_CXXFLAGS)
|
||||
|
||||
#
|
||||
# LD Flags
|
||||
#
|
||||
COMMON_LDFLAGS+=-g $(LDFLAGS)
|
||||
BOSSA_LDFLAGS=$(COMMON_LDFLAGS)
|
||||
BOSSAC_LDFLAGS=$(COMMON_LDFLAGS)
|
||||
BOSSASH_LDFLAGS=$(COMMON_LDFLAGS)
|
||||
|
||||
#
|
||||
# Libs
|
||||
#
|
||||
COMMON_LIBS+=
|
||||
WX_LIBS:=$(shell wx-config --libs --version=$(WXVERSION)) $(WX_LIBS)
|
||||
BOSSA_LIBS=$(COMMON_LIBS) $(WX_LIBS)
|
||||
BOSSAC_LIBS=$(COMMON_LIBS)
|
||||
BOSSASH_LIBS=-lreadline $(COMMON_LIBS)
|
||||
|
||||
#
|
||||
# Main targets
|
||||
#
|
||||
all: $(BINDIR)/bossa$(EXE) $(BINDIR)/bossac$(EXE) $(BINDIR)/bossash$(EXE)
|
||||
|
||||
#
|
||||
# Common rules
|
||||
#
|
||||
define common_obj
|
||||
$(OBJDIR)/$(1:%.cpp=%.o): $(SRCDIR)/$(1)
|
||||
@echo CPP COMMON $$<
|
||||
$$(Q)$$(CXX) $$(COMMON_CXXFLAGS) -c -o $$@ $$<
|
||||
endef
|
||||
$(foreach src,$(COMMON_SRCS),$(eval $(call common_obj,$(src))))
|
||||
|
||||
#
|
||||
# Applet rules
|
||||
#
|
||||
define applet_obj
|
||||
$(SRCDIR)/$(1:%.asm=%.cpp): $(SRCDIR)/$(1)
|
||||
@echo APPLET $(1:%.asm=%)
|
||||
$$(Q)$$(ARMAS) -o $$(@:$(SRCDIR)/%.cpp=$(OBJDIR)/%.obj) $$<
|
||||
$$(Q)$$(ARMOBJCOPY) -O binary $$(@:$(SRCDIR)/%.cpp=$(OBJDIR)/%.obj) $$(@:$(SRCDIR)/%.cpp=$(OBJDIR)/%.bin)
|
||||
$$(Q)./appletgen $(1:%.asm=%) $(SRCDIR) $(OBJDIR)
|
||||
$(OBJDIR)/$(1:%.asm=%.o): $(SRCDIR)/$(1:%.asm=%.cpp)
|
||||
@echo CPP APPLET $$<
|
||||
$$(Q)$$(CXX) $$(COMMON_CXXFLAGS) -c -o $$(@) $$(<:%.asm=%.cpp)
|
||||
endef
|
||||
$(foreach src,$(APPLET_SRCS),$(eval $(call applet_obj,$(src))))
|
||||
|
||||
#
|
||||
# BOSSA rules
|
||||
#
|
||||
define bossa_obj
|
||||
$(OBJDIR)/$(1:%.cpp=%.o): $(SRCDIR)/$(1)
|
||||
@echo CPP BOSSA $$<
|
||||
$$(Q)$$(CXX) $$(BOSSA_CXXFLAGS) -c -o $$@ $$<
|
||||
endef
|
||||
$(foreach src,$(BOSSA_SRCS),$(eval $(call bossa_obj,$(src))))
|
||||
|
||||
#
|
||||
# Resource rules
|
||||
#
|
||||
ifeq ($(OS),MINGW32)
|
||||
$(OBJDIR)/$(BOSSA_RC:%.rc=%.o): $(RESDIR)/$(BOSSA_RC)
|
||||
@echo RC $<
|
||||
$(Q)`wx-config --rescomp --version=$(WXVERSION)` -o $@ $<
|
||||
endif
|
||||
|
||||
#
|
||||
# BOSSAC rules
|
||||
#
|
||||
define bossac_obj
|
||||
$(OBJDIR)/$(1:%.cpp=%.o): $(SRCDIR)/$(1)
|
||||
@echo CPP BOSSAC $$<
|
||||
$$(Q)$$(CXX) $$(BOSSAC_CXXFLAGS) -c -o $$@ $$<
|
||||
endef
|
||||
$(foreach src,$(BOSSAC_SRCS),$(eval $(call bossac_obj,$(src))))
|
||||
|
||||
#
|
||||
# BOSSASH rules
|
||||
#
|
||||
define bossash_obj
|
||||
$(OBJDIR)/$(1:%.cpp=%.o): $(SRCDIR)/$(1)
|
||||
@echo CPP BOSSASH $$<
|
||||
$$(Q)$$(CXX) $$(BOSSASH_CXXFLAGS) -c -o $$@ $$<
|
||||
endef
|
||||
$(foreach src,$(BOSSASH_SRCS),$(eval $(call bossash_obj,$(src))))
|
||||
|
||||
#
|
||||
# BMP rules
|
||||
#
|
||||
define bossa_bmp
|
||||
$(SRCDIR)/$(1:%.bmp=%.cpp): $(RESDIR)/$(1)
|
||||
@echo BIN2C $$<
|
||||
$(Q)bin2c $$< $$@
|
||||
endef
|
||||
$(foreach bmp,$(BOSSA_BMPS),$(eval $(call bossa_bmp,$(bmp))))
|
||||
|
||||
#
|
||||
# Directory rules
|
||||
#
|
||||
$(OBJDIR):
|
||||
@mkdir $@
|
||||
|
||||
$(BINDIR):
|
||||
@mkdir $@
|
||||
|
||||
#
|
||||
# Target rules
|
||||
#
|
||||
$(BOSSA_OBJS): | $(OBJDIR)
|
||||
$(BINDIR)/bossa$(EXE): $(foreach bmp,$(BOSSA_BMPS),$(SRCDIR)/$(bmp:%.bmp=%.cpp)) $(BOSSA_OBJS) | $(BINDIR)
|
||||
@echo LD $@
|
||||
$(Q)$(CXX) $(BOSSA_LDFLAGS) -o $@ $(BOSSA_OBJS) $(BOSSA_LIBS)
|
||||
|
||||
$(BOSSAC_OBJS): | $(OBJDIR)
|
||||
$(BINDIR)/bossac$(EXE): $(BOSSAC_OBJS) | $(BINDIR)
|
||||
@echo LD $@
|
||||
$(Q)$(CXX) $(BOSSAC_LDFLAGS) -o $@ $(BOSSAC_OBJS) $(BOSSAC_LIBS)
|
||||
|
||||
$(BOSSASH_OBJS): | $(OBJDIR)
|
||||
$(BINDIR)/bossash$(EXE): $(BOSSASH_OBJS) | $(BINDIR)
|
||||
@echo LD $@
|
||||
$(Q)$(CXX) $(BOSSASH_LDFLAGS) -o $@ $(BOSSASH_OBJS) $(BOSSASH_LIBS)
|
||||
|
||||
strip-bossa: $(BINDIR)/bossa$(EXE)
|
||||
@echo STRIP $^
|
||||
$(Q)strip $^
|
||||
|
||||
strip-bossac: $(BINDIR)/bossac$(EXE)
|
||||
@echo STRIP $^
|
||||
$(Q)strip $^
|
||||
|
||||
strip-bossash: $(BINDIR)/bossash$(EXE)
|
||||
@echo STRIP $^
|
||||
$(Q)strip $^
|
||||
|
||||
strip: strip-bossa strip-bossac strip-bossash
|
||||
|
||||
clean:
|
||||
@echo CLEAN
|
||||
$(Q)rm -rf $(BINDIR) $(OBJDIR)
|
||||
|
||||
#
|
||||
# Include dependencies
|
||||
#
|
||||
-include $(DEPENDS)
|
|
@ -0,0 +1,64 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "Applet.h"
|
||||
|
||||
Applet::Applet(Samba& samba,
|
||||
uint32_t addr,
|
||||
uint8_t* code,
|
||||
uint32_t size,
|
||||
uint32_t start,
|
||||
uint32_t stack,
|
||||
uint32_t reset) :
|
||||
_samba(samba), _addr(addr), _size(size), _start(start), _stack(stack), _reset(reset)
|
||||
{
|
||||
_samba.write(addr, code, size);
|
||||
}
|
||||
|
||||
void
|
||||
Applet::setStack(uint32_t stack)
|
||||
{
|
||||
_samba.writeWord(_stack, stack);
|
||||
}
|
||||
|
||||
void
|
||||
Applet::run()
|
||||
{
|
||||
// Add one to the start address for Thumb mode
|
||||
_samba.go(_start + 1);
|
||||
}
|
||||
|
||||
void
|
||||
Applet::runv()
|
||||
{
|
||||
// Add one to the start address for Thumb mode
|
||||
_samba.writeWord(_reset, _start + 1);
|
||||
|
||||
// The stack is the first reset vector
|
||||
_samba.go(_stack);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _APPLET_H
|
||||
#define _APPLET_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "Samba.h"
|
||||
|
||||
class Applet
|
||||
{
|
||||
public:
|
||||
Applet(Samba& samba,
|
||||
uint32_t addr,
|
||||
uint8_t* code,
|
||||
uint32_t size,
|
||||
uint32_t start,
|
||||
uint32_t stack,
|
||||
uint32_t reset);
|
||||
virtual ~Applet() {}
|
||||
|
||||
virtual uint32_t size() { return _size; }
|
||||
virtual uint32_t addr() { return _addr; }
|
||||
|
||||
virtual void setStack(uint32_t stack);
|
||||
|
||||
virtual void run(); // To be used for Thumb-1 based devices (ARM7TDMI, ARM9)
|
||||
virtual void runv(); // To be used for Thumb-2 based devices (Cortex-Mx)
|
||||
|
||||
protected:
|
||||
Samba& _samba;
|
||||
uint32_t _addr; // Address in device SRAM where will be placed the applet
|
||||
uint32_t _size; // Applet size
|
||||
uint32_t _start; //
|
||||
uint32_t _stack; // Applet stack address in device SRAM
|
||||
uint32_t _reset;
|
||||
};
|
||||
|
||||
#endif // _APPLET_H
|
|
@ -0,0 +1,159 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "CmdOpts.h"
|
||||
|
||||
CmdOpts::CmdOpts(int argc, char* argv[], int numOpts, Option* opts) :
|
||||
_argc(argc), _argv(argv), _numOpts(numOpts), _opts(opts)
|
||||
{
|
||||
}
|
||||
|
||||
CmdOpts::~CmdOpts()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CmdOpts::usage(FILE* out)
|
||||
{
|
||||
int optIdx;
|
||||
char name[40];
|
||||
const char* start;
|
||||
const char* end;
|
||||
|
||||
for (optIdx = 0; optIdx < _numOpts; optIdx++)
|
||||
{
|
||||
if (_opts[optIdx].arg.has == ArgOptional)
|
||||
snprintf(name, sizeof(name), " -%c, --%s[=%s]",
|
||||
_opts[optIdx].letter,
|
||||
_opts[optIdx].name,
|
||||
_opts[optIdx].arg.name);
|
||||
else if (_opts[optIdx].arg.has == ArgRequired)
|
||||
snprintf(name, sizeof(name), " -%c, --%s=%s",
|
||||
_opts[optIdx].letter,
|
||||
_opts[optIdx].name,
|
||||
_opts[optIdx].arg.name);
|
||||
else
|
||||
snprintf(name, sizeof(name), " -%c, --%s",
|
||||
_opts[optIdx].letter,
|
||||
_opts[optIdx].name);
|
||||
|
||||
fprintf(out, "%-23s ", name);
|
||||
|
||||
start = _opts[optIdx].help;
|
||||
while ((end = strchr(start, '\n')))
|
||||
{
|
||||
fwrite(start, end - start + 1, 1, out);
|
||||
fprintf(out, "%24s", "");
|
||||
start = end + 1;
|
||||
}
|
||||
fprintf(out, "%s\n", start);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
CmdOpts::parse()
|
||||
{
|
||||
struct option long_opts[_numOpts + 1];
|
||||
char optstring[_numOpts * 3 + 1];
|
||||
char* optPtr = optstring;
|
||||
int optIdx;
|
||||
int rc;
|
||||
|
||||
for (optIdx = 0; optIdx < _numOpts; optIdx++)
|
||||
{
|
||||
*_opts[optIdx].present = false;
|
||||
|
||||
*optPtr++ = _opts[optIdx].letter;
|
||||
long_opts[optIdx].name = _opts[optIdx].name;
|
||||
switch (_opts[optIdx].arg.has)
|
||||
{
|
||||
default:
|
||||
case ArgNone:
|
||||
long_opts[optIdx].has_arg = no_argument;
|
||||
break;
|
||||
case ArgOptional:
|
||||
long_opts[optIdx].has_arg = optional_argument;
|
||||
*optPtr++ = ':';
|
||||
*optPtr++ = ':';
|
||||
break;
|
||||
case ArgRequired:
|
||||
long_opts[optIdx].has_arg = required_argument;
|
||||
*optPtr++ = ':';
|
||||
break;
|
||||
}
|
||||
long_opts[optIdx].flag = NULL;
|
||||
long_opts[optIdx].val = 0;
|
||||
}
|
||||
|
||||
memset(&long_opts[_numOpts], 0, sizeof(long_opts[_numOpts]));
|
||||
*optPtr = '\0';
|
||||
optIdx = 0;
|
||||
while ((rc = getopt_long(_argc, _argv, optstring, long_opts, &optIdx)) != -1)
|
||||
{
|
||||
if (rc == '?')
|
||||
return -1;
|
||||
|
||||
if (rc != 0)
|
||||
optIdx = find(rc);
|
||||
|
||||
assert(optIdx >= 0 && optIdx < _numOpts);
|
||||
*_opts[optIdx].present = true;
|
||||
if (_opts[optIdx].arg.has != ArgNone && optarg)
|
||||
{
|
||||
switch (_opts[optIdx].arg.type)
|
||||
{
|
||||
case ArgInt:
|
||||
*_opts[optIdx].arg.value.intPtr = strtol(optarg, NULL, 0);
|
||||
break;
|
||||
default:
|
||||
case ArgString:
|
||||
*_opts[optIdx].arg.value.strPtr = optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return optind;
|
||||
}
|
||||
|
||||
int
|
||||
CmdOpts::find(char letter)
|
||||
{
|
||||
int optIdx;
|
||||
|
||||
for (optIdx = 0; optIdx < _numOpts; optIdx++)
|
||||
if (_opts[optIdx].letter == letter)
|
||||
break;
|
||||
|
||||
return optIdx;
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _OPTION_H
|
||||
#define _OPTION_H
|
||||
|
||||
#include <string>
|
||||
#include <stdio.h>
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ArgNone,
|
||||
ArgOptional,
|
||||
ArgRequired
|
||||
} ArgHas;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ArgInt,
|
||||
ArgString
|
||||
} ArgType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
ArgHas has;
|
||||
ArgType type;
|
||||
const char* name;
|
||||
union
|
||||
{
|
||||
void* voidPtr;
|
||||
int* intPtr;
|
||||
std::string* strPtr;
|
||||
} value;
|
||||
} OptArg;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char letter;
|
||||
const char* name;
|
||||
bool* present;
|
||||
OptArg arg;
|
||||
const char* help;
|
||||
} Option;
|
||||
|
||||
class CmdOpts
|
||||
{
|
||||
public:
|
||||
CmdOpts(int argc, char* argv[], int numOpts, Option* opts);
|
||||
virtual ~CmdOpts();
|
||||
|
||||
void usage(FILE* out);
|
||||
int parse();
|
||||
|
||||
private:
|
||||
int _argc;
|
||||
char** _argv;
|
||||
int _numOpts;
|
||||
Option* _opts;
|
||||
|
||||
int find(char letter);
|
||||
};
|
||||
|
||||
#endif // _OPTION_H
|
|
@ -0,0 +1,347 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "D2xNvmFlash.h"
|
||||
|
||||
// CMDEX field should be 0xA5 to allow execution of any command.
|
||||
#define CMDEX_KEY 0xa500
|
||||
|
||||
// NVM ready bit mask
|
||||
#define NVM_INT_STATUS_READY_MASK 0x1
|
||||
|
||||
// NVM status mask
|
||||
#define NVM_CTRL_STATUS_MASK 0xFFEB
|
||||
|
||||
#define NVM_REG_BASE 0x41004000
|
||||
|
||||
#define NVM_REG_CTRLA 0x00
|
||||
#define NVM_REG_CTRLB 0x04
|
||||
#define NVM_REG_INTFLAG 0x14
|
||||
#define NVM_REG_STATUS 0x18
|
||||
#define NVM_REG_ADDR 0x1c
|
||||
#define NVM_REG_LOCK 0x20
|
||||
|
||||
#define NVM_CMD_ER 0x02
|
||||
#define NVM_CMD_WP 0x04
|
||||
#define NVM_CMD_EAR 0x05
|
||||
#define NVM_CMD_WAP 0x06
|
||||
#define NVM_CMD_LR 0x40
|
||||
#define NVM_CMD_UR 0x41
|
||||
#define NVM_CMD_SSB 0x45
|
||||
#define NVM_CMD_PBC 0x44
|
||||
|
||||
#define ERASE_ROW_PAGES 4 // pages
|
||||
|
||||
// NVM User Row
|
||||
#define NVM_UR_ADDR 0x804000
|
||||
#define NVM_UR_SIZE (_size * ERASE_ROW_PAGES)
|
||||
#define NVM_UR_BOD33_ENABLE_OFFSET 0x1
|
||||
#define NVM_UR_BOD33_ENABLE_MASK 0x6
|
||||
#define NVM_UR_BOD33_RESET_OFFSET 0x1
|
||||
#define NVM_UR_BOD33_RESET_MASK 0x7
|
||||
#define NVM_UR_NVM_LOCK_OFFSET 0x6
|
||||
|
||||
D2xNvmFlash::D2xNvmFlash(
|
||||
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, 16, user, stack), _eraseAuto(true)
|
||||
{
|
||||
}
|
||||
|
||||
D2xNvmFlash::~D2xNvmFlash()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
D2xNvmFlash::erase(uint32_t offset, uint32_t size)
|
||||
{
|
||||
uint32_t eraseSize = _size * ERASE_ROW_PAGES;
|
||||
|
||||
// Offset must be a multiple of the erase size
|
||||
if (offset % eraseSize)
|
||||
throw FlashEraseError();
|
||||
|
||||
// Offset and size must be in range
|
||||
if (offset + size > totalSize())
|
||||
throw FlashEraseError();
|
||||
|
||||
uint32_t eraseEnd = (offset + size + eraseSize - 1) / eraseSize;
|
||||
|
||||
// Erase each erase size set of pages
|
||||
for (uint32_t eraseNum = offset / eraseSize; eraseNum < eraseEnd; eraseNum++)
|
||||
{
|
||||
waitReady();
|
||||
|
||||
// Clear error bits
|
||||
uint16_t statusReg = readReg(NVM_REG_STATUS);
|
||||
writeReg(NVM_REG_STATUS, statusReg | NVM_CTRL_STATUS_MASK);
|
||||
|
||||
// Issue erase command
|
||||
uint32_t wordAddr = (eraseNum * eraseSize) / 2;
|
||||
writeReg(NVM_REG_ADDR, wordAddr);
|
||||
command(NVM_CMD_ER);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
D2xNvmFlash::eraseAll(uint32_t offset)
|
||||
{
|
||||
// Use the extended Samba command if available
|
||||
if (_samba.canChipErase())
|
||||
{
|
||||
_samba.chipErase(offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
erase(offset, totalSize() - offset);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
D2xNvmFlash::eraseAuto(bool enable)
|
||||
{
|
||||
_eraseAuto = enable;
|
||||
}
|
||||
|
||||
std::vector<bool>
|
||||
D2xNvmFlash::getLockRegions()
|
||||
{
|
||||
uint8_t lockBits = 0;
|
||||
uint32_t addr = NVM_UR_ADDR + NVM_UR_NVM_LOCK_OFFSET;
|
||||
std::vector<bool> regions(_lockRegions);
|
||||
|
||||
for (uint32_t region = 0; region < _lockRegions; region++)
|
||||
{
|
||||
if (region % 8 == 0)
|
||||
lockBits = _samba.readByte(addr++);
|
||||
regions[region] = (lockBits & (1 << (region % 8))) == 0;
|
||||
}
|
||||
|
||||
return regions;
|
||||
}
|
||||
|
||||
bool
|
||||
D2xNvmFlash::getSecurity()
|
||||
{
|
||||
return (readReg(NVM_REG_STATUS) & 0x100) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
D2xNvmFlash::getBod()
|
||||
{
|
||||
uint8_t byte = _samba.readByte(NVM_UR_ADDR + NVM_UR_BOD33_ENABLE_OFFSET);
|
||||
|
||||
return (byte & NVM_UR_BOD33_ENABLE_MASK) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
D2xNvmFlash::getBor()
|
||||
{
|
||||
uint8_t byte = _samba.readByte(NVM_UR_ADDR + NVM_UR_BOD33_RESET_OFFSET);
|
||||
|
||||
return (byte & NVM_UR_BOD33_RESET_MASK) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
D2xNvmFlash::getBootFlash()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
D2xNvmFlash::readUserRow(std::unique_ptr<uint8_t[]>& userRow)
|
||||
{
|
||||
if (!userRow)
|
||||
{
|
||||
userRow.reset(new uint8_t[NVM_UR_SIZE]);
|
||||
_samba.read(NVM_UR_ADDR, userRow.get(), NVM_UR_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
D2xNvmFlash::writeOptions()
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> userRow;
|
||||
|
||||
if (canBor() && _bor.isDirty() && _bor.get() != getBor())
|
||||
{
|
||||
readUserRow(userRow);
|
||||
if (_bor.get())
|
||||
userRow[NVM_UR_BOD33_RESET_OFFSET] |= NVM_UR_BOD33_RESET_MASK;
|
||||
else
|
||||
userRow[NVM_UR_BOD33_RESET_OFFSET] &= ~NVM_UR_BOD33_RESET_MASK;
|
||||
}
|
||||
if (canBod() && _bod.isDirty() && _bod.get() != getBod())
|
||||
{
|
||||
readUserRow(userRow);
|
||||
if (_bod.get())
|
||||
userRow[NVM_UR_BOD33_ENABLE_OFFSET] |= NVM_UR_BOD33_ENABLE_MASK;
|
||||
else
|
||||
userRow[NVM_UR_BOD33_ENABLE_OFFSET] &= ~NVM_UR_BOD33_ENABLE_MASK;
|
||||
}
|
||||
if (_regions.isDirty())
|
||||
{
|
||||
// Check if any lock bits are different from the current set
|
||||
std::vector<bool> current = getLockRegions();
|
||||
if (!equal(_regions.get().begin(), _regions.get().end(), current.begin()))
|
||||
{
|
||||
readUserRow(userRow);
|
||||
|
||||
uint8_t* lockBits = &userRow[NVM_UR_NVM_LOCK_OFFSET];
|
||||
for (uint32_t region = 0; region < _regions.get().size(); region++)
|
||||
{
|
||||
if (_regions.get()[region])
|
||||
lockBits[region / 8] &= ~(1 << (region % 8));
|
||||
else
|
||||
lockBits[region / 8] |= (1 << (region % 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Erase and write the user row if modified
|
||||
if (userRow)
|
||||
{
|
||||
// Disable cache and configure manual page write
|
||||
writeReg(NVM_REG_CTRLB, readReg(NVM_REG_CTRLB) | (0x1 << 18) | (0x1 << 7));
|
||||
|
||||
// Erase user row
|
||||
writeReg(NVM_REG_ADDR, NVM_UR_ADDR / 2);
|
||||
command(NVM_CMD_EAR);
|
||||
|
||||
// Write user row in page chunks
|
||||
for (uint32_t offset = 0; offset < NVM_UR_SIZE; offset += _size)
|
||||
{
|
||||
// Load the buffer with the page
|
||||
loadBuffer(&userRow[offset], _size);
|
||||
|
||||
// Clear page buffer
|
||||
command(NVM_CMD_PBC);
|
||||
|
||||
// Copy page to page buffer
|
||||
_wordCopy.setDstAddr(NVM_UR_ADDR + offset);
|
||||
_wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB);
|
||||
_onBufferA = !_onBufferA;
|
||||
waitReady();
|
||||
_wordCopy.runv();
|
||||
|
||||
// Write the page
|
||||
writeReg(NVM_REG_ADDR, (NVM_UR_ADDR + offset) / 2);
|
||||
command(NVM_CMD_WAP);
|
||||
}
|
||||
}
|
||||
|
||||
// Always do security last
|
||||
if (_security.isDirty() && _security.get() == true && _security.get() != getSecurity())
|
||||
{
|
||||
command(NVM_CMD_SSB);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
D2xNvmFlash::writePage(uint32_t page)
|
||||
{
|
||||
if (page >= _pages)
|
||||
{
|
||||
throw FlashPageError();
|
||||
}
|
||||
|
||||
// Disable cache and configure manual page write
|
||||
writeReg(NVM_REG_CTRLB, readReg(NVM_REG_CTRLB) | (0x1 << 18) | (0x1 << 7));
|
||||
|
||||
// Auto-erase if writing at the start of the erase page
|
||||
if (_eraseAuto && page % ERASE_ROW_PAGES == 0)
|
||||
erase(page * _size, ERASE_ROW_PAGES * _size);
|
||||
|
||||
// Clear page buffer
|
||||
command(NVM_CMD_PBC);
|
||||
|
||||
// Compute the start address.
|
||||
uint32_t addr = _addr + (page * _size);
|
||||
|
||||
_wordCopy.setDstAddr(addr);
|
||||
_wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB);
|
||||
_onBufferA = !_onBufferA;
|
||||
waitReady();
|
||||
_wordCopy.runv();
|
||||
|
||||
writeReg(NVM_REG_ADDR, addr / 2);
|
||||
command(NVM_CMD_WP);
|
||||
}
|
||||
|
||||
void
|
||||
D2xNvmFlash::waitReady()
|
||||
{
|
||||
while ((readReg(NVM_REG_INTFLAG) & 0x1) == 0);
|
||||
}
|
||||
|
||||
void
|
||||
D2xNvmFlash::readPage(uint32_t page, uint8_t* buf)
|
||||
{
|
||||
if (page >= _pages)
|
||||
{
|
||||
throw FlashPageError();
|
||||
}
|
||||
|
||||
_samba.read(_addr + (page * _size), buf, _size);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
D2xNvmFlash::readReg(uint8_t reg)
|
||||
{
|
||||
return _samba.readWord(NVM_REG_BASE + reg);
|
||||
}
|
||||
|
||||
void
|
||||
D2xNvmFlash::writeReg(uint8_t reg, uint32_t value)
|
||||
{
|
||||
_samba.writeWord(NVM_REG_BASE + reg, value);
|
||||
}
|
||||
|
||||
void
|
||||
D2xNvmFlash::command(uint8_t cmd)
|
||||
{
|
||||
waitReady();
|
||||
|
||||
writeReg(NVM_REG_CTRLA, CMDEX_KEY | cmd);
|
||||
|
||||
waitReady();
|
||||
|
||||
if (readReg(NVM_REG_INTFLAG) & 0x2)
|
||||
{
|
||||
// Clear the error bit
|
||||
writeReg(NVM_REG_INTFLAG, 0x2);
|
||||
throw FlashCmdError();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
D2xNvmFlash::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);
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _D2XNVMFLASH_H
|
||||
#define _D2XNVMFLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <exception>
|
||||
|
||||
#include "Flash.h"
|
||||
|
||||
class D2xNvmFlash : public Flash
|
||||
{
|
||||
public:
|
||||
D2xNvmFlash(
|
||||
Samba& samba,
|
||||
const std::string& name,
|
||||
uint32_t pages,
|
||||
uint32_t size,
|
||||
uint32_t user,
|
||||
uint32_t stack);
|
||||
|
||||
virtual ~D2xNvmFlash();
|
||||
|
||||
void eraseAll(uint32_t offset);
|
||||
void eraseAuto(bool enable);
|
||||
|
||||
std::vector<bool> getLockRegions();
|
||||
|
||||
bool getSecurity();
|
||||
|
||||
bool getBod();
|
||||
bool canBod() { return true; }
|
||||
|
||||
bool getBor();
|
||||
bool canBor() { return true; }
|
||||
|
||||
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;
|
||||
|
||||
uint32_t readReg(uint8_t reg);
|
||||
void writeReg(uint8_t reg, uint32_t value);
|
||||
|
||||
void waitReady();
|
||||
void command(uint8_t cmd);
|
||||
void erase(uint32_t offset, uint32_t size);
|
||||
void readUserRow(std::unique_ptr<uint8_t[]>& userRow);
|
||||
};
|
||||
|
||||
#endif // _D2XNVMFLASH_H
|
|
@ -0,0 +1,352 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "D5xNvmFlash.h"
|
||||
|
||||
|
||||
#define CMDEX_KEY 0xa500
|
||||
|
||||
#define NVM_REG_BASE 0x41004000
|
||||
|
||||
#define NVM_REG_CTRLA 0x00
|
||||
#define NVM_REG_CTRLB 0x04
|
||||
#define NVM_REG_INTFLAG 0x10
|
||||
#define NVM_REG_STATUS 0x12
|
||||
#define NVM_REG_ADDR 0x14
|
||||
#define NVM_REG_RUNLOCK 0x18
|
||||
|
||||
#define NVM_CMD_EP 0x00
|
||||
#define NVM_CMD_EB 0x01
|
||||
#define NVM_CMD_WP 0x03
|
||||
#define NVM_CMD_WQW 0x04
|
||||
#define NVM_CMD_LR 0x11
|
||||
#define NVM_CMD_UR 0x12
|
||||
#define NVM_CMD_SSB 0x16
|
||||
#define NVM_CMD_PBC 0x15
|
||||
|
||||
#define ERASE_BLOCK_PAGES 16 // pages
|
||||
|
||||
// NVM User Page
|
||||
#define NVM_UP_ADDR 0x804000
|
||||
#define NVM_UP_SIZE (_size)
|
||||
#define NVM_UP_BOD33_DISABLE_OFFSET 0x0
|
||||
#define NVM_UP_BOD33_DISABLE_MASK 0x1
|
||||
#define NVM_UP_BOD33_RESET_OFFSET 0x1
|
||||
#define NVM_UP_BOD33_RESET_MASK 0x2
|
||||
#define NVM_UP_NVM_LOCK_OFFSET 0x8
|
||||
|
||||
D5xNvmFlash::D5xNvmFlash(
|
||||
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, 32, user, stack), _eraseAuto(true)
|
||||
{
|
||||
}
|
||||
|
||||
D5xNvmFlash::~D5xNvmFlash()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
D5xNvmFlash::erase(uint32_t offset, uint32_t size)
|
||||
{
|
||||
uint32_t eraseSize = _size * ERASE_BLOCK_PAGES;
|
||||
|
||||
// Offset must be a multiple of the erase size
|
||||
if (offset % eraseSize)
|
||||
throw FlashEraseError();
|
||||
|
||||
// Offset and size must be in range
|
||||
if (offset + size > totalSize())
|
||||
throw FlashEraseError();
|
||||
|
||||
uint32_t eraseEnd = (offset + size + eraseSize - 1) / eraseSize;
|
||||
|
||||
// Erase each erase size set of pages
|
||||
for (uint32_t eraseNum = offset / eraseSize; eraseNum < eraseEnd; eraseNum++)
|
||||
{
|
||||
// Issue erase command
|
||||
writeRegU32(NVM_REG_ADDR, eraseNum * eraseSize);
|
||||
command(NVM_CMD_EB);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
D5xNvmFlash::eraseAll(uint32_t offset)
|
||||
{
|
||||
// Use the extended Samba command if available
|
||||
if (_samba.canChipErase())
|
||||
{
|
||||
_samba.chipErase(offset);
|
||||
}
|
||||
else
|
||||
{
|
||||
erase(offset, totalSize() - offset);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
D5xNvmFlash::waitReady()
|
||||
{
|
||||
while ((readRegU16(NVM_REG_STATUS) & 0x1) == 0);
|
||||
}
|
||||
|
||||
void
|
||||
D5xNvmFlash::eraseAuto(bool enable)
|
||||
{
|
||||
_eraseAuto = enable;
|
||||
}
|
||||
|
||||
std::vector<bool>
|
||||
D5xNvmFlash::getLockRegions()
|
||||
{
|
||||
uint8_t lockBits = 0;
|
||||
uint32_t addr = NVM_UP_ADDR + NVM_UP_NVM_LOCK_OFFSET;
|
||||
std::vector<bool> regions(_lockRegions);
|
||||
|
||||
for (uint32_t region = 0; region < _lockRegions; region++)
|
||||
{
|
||||
if (region % 8 == 0)
|
||||
lockBits = _samba.readByte(addr++);
|
||||
regions[region] = (lockBits & (1 << (region % 8))) == 0;
|
||||
}
|
||||
|
||||
return regions;
|
||||
}
|
||||
|
||||
bool
|
||||
D5xNvmFlash::getSecurity()
|
||||
{
|
||||
// There doesn't seem to be a way to read this
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
D5xNvmFlash::getBod()
|
||||
{
|
||||
uint8_t byte = _samba.readByte(NVM_UP_ADDR + NVM_UP_BOD33_DISABLE_OFFSET);
|
||||
|
||||
return (byte & NVM_UP_BOD33_DISABLE_MASK) == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
D5xNvmFlash::getBor()
|
||||
{
|
||||
uint8_t byte = _samba.readByte(NVM_UP_ADDR + NVM_UP_BOD33_RESET_OFFSET);
|
||||
|
||||
return (byte & NVM_UP_BOD33_RESET_MASK) != 0;
|
||||
}
|
||||
|
||||
bool
|
||||
D5xNvmFlash::getBootFlash()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
D5xNvmFlash::readUserPage(std::unique_ptr<uint8_t[]>& userPage)
|
||||
{
|
||||
if (!userPage)
|
||||
{
|
||||
userPage.reset(new uint8_t[NVM_UP_SIZE]);
|
||||
_samba.read(NVM_UP_ADDR, userPage.get(), NVM_UP_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
D5xNvmFlash::writeOptions()
|
||||
{
|
||||
std::unique_ptr<uint8_t[]> userPage;
|
||||
|
||||
if (canBor() && _bor.isDirty() && _bor.get() != getBor())
|
||||
{
|
||||
readUserPage(userPage);
|
||||
if (_bor.get())
|
||||
userPage[NVM_UP_BOD33_RESET_OFFSET] |= NVM_UP_BOD33_RESET_MASK;
|
||||
else
|
||||
userPage[NVM_UP_BOD33_RESET_OFFSET] &= ~NVM_UP_BOD33_RESET_MASK;
|
||||
}
|
||||
if (canBod() && _bod.isDirty() && _bod.get() != getBod())
|
||||
{
|
||||
readUserPage(userPage);
|
||||
if (_bod.get())
|
||||
userPage[NVM_UP_BOD33_DISABLE_OFFSET] &= ~NVM_UP_BOD33_DISABLE_MASK;
|
||||
else
|
||||
userPage[NVM_UP_BOD33_DISABLE_OFFSET] |= NVM_UP_BOD33_DISABLE_MASK;
|
||||
}
|
||||
if (_regions.isDirty())
|
||||
{
|
||||
// Check if any lock bits are different from the current set
|
||||
std::vector<bool> current = getLockRegions();
|
||||
if (!equal(_regions.get().begin(), _regions.get().end(), current.begin()))
|
||||
{
|
||||
readUserPage(userPage);
|
||||
|
||||
uint8_t* lockBits = &userPage[NVM_UP_NVM_LOCK_OFFSET];
|
||||
for (uint32_t region = 0; region < _regions.get().size(); region++)
|
||||
{
|
||||
if (_regions.get()[region])
|
||||
lockBits[region / 8] &= ~(1 << (region % 8));
|
||||
else
|
||||
lockBits[region / 8] |= (1 << (region % 8));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Erase and write the user page if modified
|
||||
if (userPage)
|
||||
{
|
||||
// Configure manual page write and disable caches
|
||||
writeRegU16(NVM_REG_CTRLA, (readRegU16(NVM_REG_CTRLA) | (0x3 << 14)) & 0xffcf);
|
||||
|
||||
// Erase user page
|
||||
writeRegU32(NVM_REG_ADDR, NVM_UP_ADDR);
|
||||
command(NVM_CMD_EP);
|
||||
|
||||
// Write user page in quad-word chunks
|
||||
for (uint32_t offset = 0; offset < NVM_UP_SIZE; offset += 16)
|
||||
{
|
||||
// Load the buffer with the quad word
|
||||
loadBuffer(&userPage[offset], 16);
|
||||
|
||||
// Clear page buffer
|
||||
command(NVM_CMD_PBC);
|
||||
|
||||
// Copy quad word to page buffer
|
||||
_wordCopy.setDstAddr(NVM_UP_ADDR + offset);
|
||||
_wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB);
|
||||
_wordCopy.setWords(4);
|
||||
_onBufferA = !_onBufferA;
|
||||
waitReady();
|
||||
_wordCopy.runv();
|
||||
|
||||
// Write the quad word
|
||||
writeRegU32(NVM_REG_ADDR, NVM_UP_ADDR + offset);
|
||||
command(NVM_CMD_WQW);
|
||||
}
|
||||
}
|
||||
|
||||
// Always do security last
|
||||
if (_security.isDirty() && _security.get() == true && _security.get() != getSecurity())
|
||||
{
|
||||
command(NVM_CMD_SSB);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
D5xNvmFlash::writePage(uint32_t page)
|
||||
{
|
||||
if (page >= _pages)
|
||||
{
|
||||
throw FlashPageError();
|
||||
}
|
||||
|
||||
// Configure manual page write and disable caches
|
||||
writeRegU16(NVM_REG_CTRLA, (readRegU16(NVM_REG_CTRLA) | (0x3 << 14)) & 0xffcf);
|
||||
|
||||
// Auto-erase if writing at the start of the erase page
|
||||
if (_eraseAuto && page % ERASE_BLOCK_PAGES == 0)
|
||||
{
|
||||
erase(page * _size, ERASE_BLOCK_PAGES * _size);
|
||||
}
|
||||
|
||||
// Clear page bur
|
||||
command(NVM_CMD_PBC);
|
||||
|
||||
uint32_t addr = _addr + (page * _size );
|
||||
|
||||
_wordCopy.setDstAddr(addr);
|
||||
_wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB);
|
||||
_wordCopy.setWords(_size / sizeof(uint32_t));
|
||||
_onBufferA = !_onBufferA;
|
||||
waitReady();
|
||||
_wordCopy.runv();
|
||||
|
||||
writeRegU32(NVM_REG_ADDR, addr);
|
||||
command(NVM_CMD_WP);
|
||||
}
|
||||
|
||||
void
|
||||
D5xNvmFlash::readPage(uint32_t page, uint8_t* buf)
|
||||
{
|
||||
if (page >= _pages)
|
||||
{
|
||||
throw FlashPageError();
|
||||
}
|
||||
|
||||
_samba.read(_addr + (page * _size), buf, _size);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
D5xNvmFlash::readRegU16(uint8_t reg)
|
||||
{
|
||||
return (uint16_t) _samba.readByte(NVM_REG_BASE + reg) |
|
||||
(_samba.readByte(NVM_REG_BASE + reg + 1) << 8);
|
||||
}
|
||||
|
||||
void
|
||||
D5xNvmFlash::writeRegU16(uint8_t reg, uint16_t value)
|
||||
{
|
||||
_samba.writeByte(NVM_REG_BASE + reg, value & 0xff);
|
||||
_samba.writeByte(NVM_REG_BASE + reg + 1, value >> 8);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
D5xNvmFlash::readRegU32(uint8_t reg)
|
||||
{
|
||||
return _samba.readWord(NVM_REG_BASE + reg);
|
||||
}
|
||||
|
||||
void
|
||||
D5xNvmFlash::writeRegU32(uint8_t reg, uint32_t value)
|
||||
{
|
||||
_samba.writeWord(NVM_REG_BASE + reg, value);
|
||||
}
|
||||
|
||||
void
|
||||
D5xNvmFlash::command(uint8_t cmd)
|
||||
{
|
||||
waitReady();
|
||||
|
||||
writeRegU32(NVM_REG_CTRLB, CMDEX_KEY | cmd);
|
||||
|
||||
waitReady();
|
||||
|
||||
if (readRegU16(NVM_REG_INTFLAG) & 0xce)
|
||||
{
|
||||
// Clear the error bits
|
||||
writeRegU16(NVM_REG_INTFLAG, 0xce);
|
||||
throw FlashCmdError();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
D5xNvmFlash::writeBuffer(uint32_t dst_addr, uint32_t size)
|
||||
{
|
||||
// Auto-erase if writing at the start of the erase page
|
||||
if (_eraseAuto && ((dst_addr / _size) % ERASE_BLOCK_PAGES == 0))
|
||||
erase(dst_addr, size);
|
||||
|
||||
// Call the base class method
|
||||
Flash::writeBuffer(dst_addr, size);
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _D5XNVMFLASH_H
|
||||
#define _D5XNVMFLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <exception>
|
||||
|
||||
#include "Flash.h"
|
||||
|
||||
class D5xNvmFlash : public Flash
|
||||
{
|
||||
public:
|
||||
D5xNvmFlash(
|
||||
Samba& samba,
|
||||
const std::string& name,
|
||||
uint32_t pages,
|
||||
uint32_t size,
|
||||
uint32_t user,
|
||||
uint32_t stack);
|
||||
|
||||
virtual ~D5xNvmFlash();
|
||||
|
||||
void eraseAll(uint32_t offset);
|
||||
void eraseAuto(bool enable);
|
||||
|
||||
std::vector<bool> getLockRegions();
|
||||
|
||||
bool getSecurity();
|
||||
|
||||
bool getBod();
|
||||
bool canBod() { return true; }
|
||||
|
||||
bool getBor();
|
||||
bool canBor() { return true; }
|
||||
|
||||
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;
|
||||
|
||||
uint16_t readRegU16(uint8_t reg);
|
||||
void writeRegU16(uint8_t reg, uint16_t value);
|
||||
uint32_t readRegU32(uint8_t reg);
|
||||
void writeRegU32(uint8_t reg, uint32_t value);
|
||||
|
||||
void waitReady();
|
||||
void command(uint8_t cmd);
|
||||
void erase(uint32_t offset, uint32_t size);
|
||||
void checkError();
|
||||
void readUserPage(std::unique_ptr<uint8_t[]>& userPage);
|
||||
};
|
||||
|
||||
#endif // _D5XNVMFLASH_H
|
|
@ -0,0 +1,692 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "Device.h"
|
||||
#include "EfcFlash.h"
|
||||
#include "EefcFlash.h"
|
||||
#include "D2xNvmFlash.h"
|
||||
#include "D5xNvmFlash.h"
|
||||
|
||||
void
|
||||
Device::readChipId(uint32_t& chipId, uint32_t& extChipId)
|
||||
{
|
||||
if ((chipId = _samba.readWord(0x400e0740)) != 0)
|
||||
{
|
||||
extChipId = _samba.readWord(0x400e0744);
|
||||
}
|
||||
else if ((chipId = _samba.readWord(0x400e0940)) != 0)
|
||||
{
|
||||
extChipId = _samba.readWord(0x400e0944);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Device::create()
|
||||
{
|
||||
Flash* flashPtr;
|
||||
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)
|
||||
{
|
||||
chipId = _samba.readWord(0xfffff240);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Next try the ARM CPUID register since all Cortex-M devices support it
|
||||
cpuId = _samba.readWord(0xe000ed00) & 0x0000fff0;
|
||||
|
||||
// Cortex-M0+
|
||||
if (cpuId == 0xC600)
|
||||
{
|
||||
// These should support the ARM device ID register
|
||||
deviceId = _samba.readWord(0x41002018);
|
||||
}
|
||||
// Cortex-M4
|
||||
else if (cpuId == 0xC240)
|
||||
{
|
||||
// SAM4 processors have a reset vector to the SAM-BA ROM
|
||||
if ((_samba.readWord(0x4) & 0xfff00000) == 0x800000)
|
||||
{
|
||||
readChipId(chipId, extChipId);
|
||||
}
|
||||
// Else we should have a device that supports the ARM device ID register
|
||||
else
|
||||
{
|
||||
deviceId = _samba.readWord(0x41002018);
|
||||
}
|
||||
}
|
||||
// For all other Cortex versions try the Atmel chip ID registers
|
||||
else
|
||||
{
|
||||
readChipId(chipId, extChipId);
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate the proper flash for the device
|
||||
switch (chipId & 0x7fffffe0)
|
||||
{
|
||||
//
|
||||
// SAM7SE
|
||||
//
|
||||
case 0x272a0a40:
|
||||
_family = FAMILY_SAM7SE;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAM7SE512", 0x100000, 2048, 256, 2, 32, 0x202000, 0x208000, true);
|
||||
break;
|
||||
case 0x272a0940:
|
||||
_family = FAMILY_SAM7SE;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAM7SE256", 0x100000, 1024, 256, 1, 16, 0x202000, 0x208000, true);
|
||||
break;
|
||||
case 0x272a0340:
|
||||
_family = FAMILY_SAM7SE;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAM7SE32", 0x100000, 256, 128, 1, 8, 0x201400, 0x201C00, true);
|
||||
break;
|
||||
//
|
||||
// SAM7S
|
||||
//
|
||||
case 0x270b0a40:
|
||||
_family = FAMILY_SAM7S;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAM7S512", 0x100000, 2048, 256, 2, 32, 0x202000, 0x210000, false);
|
||||
break;
|
||||
case 0x270d0940: // A
|
||||
case 0x270b0940: // B/C
|
||||
_family = FAMILY_SAM7S;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAM7S256", 0x100000, 1024, 256, 1, 16, 0x202000, 0x210000, false);
|
||||
break;
|
||||
case 0x270c0740: // A
|
||||
case 0x270a0740: // B/C
|
||||
_family = FAMILY_SAM7S;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAM7S128", 0x100000, 512, 256, 1, 8, 0x202000, 0x208000, false);
|
||||
break;
|
||||
case 0x27090540:
|
||||
_family = FAMILY_SAM7S;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAM7S64", 0x100000, 512, 128, 1, 16, 0x202000, 0x204000, false);
|
||||
break;
|
||||
case 0x27080340:
|
||||
_family = FAMILY_SAM7S;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAM7S32", 0x100000, 256, 128, 1, 8, 0x201400, 0x202000, false);
|
||||
break;
|
||||
case 0x27050240:
|
||||
_family = FAMILY_SAM7S;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAM7S16", 0x100000, 256, 64, 1, 8, 0x200000, 0x200e00, false);
|
||||
break;
|
||||
//
|
||||
// SAM7XC
|
||||
//
|
||||
case 0x271c0a40:
|
||||
_family = FAMILY_SAM7XC;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAMXC512", 0x100000, 2048, 256, 2, 32, 0x202000, 0x220000, true);
|
||||
break;
|
||||
case 0x271b0940:
|
||||
_family = FAMILY_SAM7XC;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAMXC256", 0x100000, 1024, 256, 1, 16, 0x202000, 0x210000, true);
|
||||
break;
|
||||
case 0x271a0740:
|
||||
_family = FAMILY_SAM7XC;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAMXC128", 0x100000, 512, 256, 1, 8, 0x202000, 0x208000, true);
|
||||
break;
|
||||
//
|
||||
// SAM7X
|
||||
//
|
||||
case 0x275c0a40:
|
||||
_family = FAMILY_SAM7X;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAMX512", 0x100000, 2048, 256, 2, 32, 0x202000, 0x220000, true);
|
||||
break;
|
||||
case 0x275b0940:
|
||||
_family = FAMILY_SAM7X;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAMX256", 0x100000, 1024, 256, 1, 16, 0x202000, 0x210000, true);
|
||||
break;
|
||||
case 0x275a0740:
|
||||
_family = FAMILY_SAM7X;
|
||||
flashPtr = new EfcFlash(_samba, "AT91SAMX128", 0x100000, 512, 256, 1, 8, 0x202000, 0x208000, true);
|
||||
break;
|
||||
//
|
||||
// SAM4S
|
||||
//
|
||||
case 0x29870ee0: // A
|
||||
case 0x29970ee0: // B
|
||||
case 0x29A70ee0: // C
|
||||
_family = FAMILY_SAM4S;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM4SD32", 0x400000, 4096, 512, 2, 256, 0x20001000, 0x20010000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x29870c30: // A
|
||||
case 0x29970c30: // B
|
||||
case 0x29a70c30: // C
|
||||
_family = FAMILY_SAM4S;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM4SD16", 0x400000, 2048, 512, 2, 256, 0x20001000, 0x20010000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x28870ce0: // A
|
||||
case 0x28970ce0: // B
|
||||
case 0x28A70ce0: // C
|
||||
_family = FAMILY_SAM4S;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM4SA16", 0x400000, 2048, 512, 1, 256, 0x20001000, 0x20010000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x288c0ce0 : // A
|
||||
case 0x289c0ce0 : // B
|
||||
case 0x28ac0ce0 : // C
|
||||
_family = FAMILY_SAM4S;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM4S16", 0x400000, 2048, 512, 1, 128, 0x20001000, 0x20020000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x288c0ae0 : // A
|
||||
case 0x289c0ae0 : // B
|
||||
case 0x28ac0ae0 : // C
|
||||
_family = FAMILY_SAM4S;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM4S8", 0x400000, 1024, 512, 1, 64, 0x20001000, 0x20020000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x288b09e0 : // A
|
||||
case 0x289b09e0 : // B
|
||||
case 0x28ab09e0 : // C
|
||||
_family = FAMILY_SAM4S;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM4S4", 0x400000, 512, 512, 1, 16, 0x20001000, 0x20010000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x288b07e0 : // A
|
||||
case 0x289b07e0 : // B
|
||||
case 0x28ab07e0 : // C
|
||||
_family = FAMILY_SAM4S;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM4S2", 0x400000, 256, 512, 1, 16, 0x20001000, 0x20010000, 0x400e0a00, false);
|
||||
break;
|
||||
//
|
||||
// SAM3N
|
||||
//
|
||||
case 0x29340960 : // A
|
||||
case 0x29440960 : // B
|
||||
case 0x29540960 : // C
|
||||
_family = FAMILY_SAM3N;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3N4", 0x400000, 1024, 256, 1, 16, 0x20001000, 0x20006000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x29390760 : // A
|
||||
case 0x29490760 : // B
|
||||
case 0x29590760 : // C
|
||||
_family = FAMILY_SAM3N;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3N2", 0x400000, 512, 256, 1, 8, 0x20001000, 0x20004000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x29380560 : // A
|
||||
case 0x29480560 : // B
|
||||
case 0x29580560 : // C
|
||||
_family = FAMILY_SAM3N;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3N1", 0x400000, 256, 256, 1, 4, 0x20000800, 0x20002000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x29380360 : // A
|
||||
case 0x29480360 : // B
|
||||
case 0x29580360 : // C
|
||||
_family = FAMILY_SAM3N;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3N0", 0x400000, 128, 256, 1, 1, 0x20000800, 0x20002000, 0x400e0a00, false);
|
||||
break;
|
||||
//
|
||||
// SAM3S
|
||||
//
|
||||
case 0x299b0a60 : // B
|
||||
case 0x29ab0a60 : // C
|
||||
_family = FAMILY_SAM3S;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3SD8", 0x400000, 2048, 256, 1, 16, 0x20001000, 0x20010000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x289b0a60 : // B
|
||||
case 0x28ab0a60 : // C
|
||||
_family = FAMILY_SAM3S;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3S8", 0x400000, 2048, 256, 1, 16, 0x20001000, 0x20010000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x28800960 : // A
|
||||
case 0x28900960 : // B
|
||||
case 0x28a00960 : // C
|
||||
_family = FAMILY_SAM3S;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3S4", 0x400000, 1024, 256, 1, 16, 0x20001000, 0x2000c000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x288a0760 : // A
|
||||
case 0x289a0760 : // B
|
||||
case 0x28aa0760 : // C
|
||||
_family = FAMILY_SAM3S;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3S2", 0x400000, 512, 256, 1, 8, 0x20000800, 0x20008000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x288a0560 : // A
|
||||
case 0x289a0560 : // B
|
||||
case 0x28aa0560 : // C
|
||||
_family = FAMILY_SAM3S;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3S1", 0x400000, 256, 256, 1, 4, 0x20000800, 0x20004000, 0x400e0a00, false);
|
||||
break;
|
||||
//
|
||||
// SAM3U
|
||||
//
|
||||
case 0x28000960 : // C
|
||||
case 0x28100960 : // E
|
||||
_family = FAMILY_SAM3U;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3U4", 0xE0000, 1024, 256, 2, 32, 0x20001000, 0x20008000, 0x400e0800, false);
|
||||
break;
|
||||
case 0x280a0760 : // C
|
||||
case 0x281a0760 : // E
|
||||
_family = FAMILY_SAM3U;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3U2", 0x80000, 512, 256, 1, 16, 0x20001000, 0x20004000, 0x400e0800, false);
|
||||
break;
|
||||
case 0x28090560 : // C
|
||||
case 0x28190560 : // E
|
||||
_family = FAMILY_SAM3U;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3U1", 0x80000, 256, 256, 1, 8, 0x20001000, 0x20002000, 0x400e0800, false);
|
||||
break;
|
||||
//
|
||||
// SAM3X
|
||||
//
|
||||
case 0x286e0a60 : // 8H
|
||||
case 0x285e0a60 : // 8E
|
||||
case 0x284e0a60 : // 8C
|
||||
_family = FAMILY_SAM3X;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3X8", 0x80000, 2048, 256, 2, 32, 0x20001000, 0x20010000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x285b0960 : // 4E
|
||||
case 0x284b0960 : // 4C
|
||||
_family = FAMILY_SAM3X;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3X4", 0x80000, 1024, 256, 2, 16, 0x20001000, 0x20008000, 0x400e0a00, false);
|
||||
break;
|
||||
//
|
||||
// SAM3A
|
||||
//
|
||||
case 0x283e0A60 : // 8C
|
||||
_family = FAMILY_SAM3A;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3A8", 0x80000, 2048, 256, 2, 32, 0x20001000, 0x20010000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x283b0960 : // 4C
|
||||
_family = FAMILY_SAM3A;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM3A4", 0x80000, 1024, 256, 2, 16, 0x20001000, 0x20008000, 0x400e0a00, false);
|
||||
break;
|
||||
//
|
||||
// SAM7L
|
||||
//
|
||||
case 0x27330740 :
|
||||
_family = FAMILY_SAM7L;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM7L128", 0x100000, 512, 256, 1, 16, 0x2ffb40, 0x300700, 0xffffff60, false);
|
||||
break;
|
||||
case 0x27330540 :
|
||||
_family = FAMILY_SAM7L;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM7L64", 0x100000, 256, 256, 1, 8, 0x2ffb40, 0x300700, 0xffffff60, false);
|
||||
break;
|
||||
//
|
||||
// SAM9XE
|
||||
//
|
||||
case 0x329aa3a0 :
|
||||
_family = FAMILY_SAM9XE;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM9XE512", 0x200000, 1024, 512, 1, 32, 0x300000, 0x307000, 0xfffffa00, true);
|
||||
break;
|
||||
case 0x329a93a0 :
|
||||
_family = FAMILY_SAM9XE;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM9XE256", 0x200000, 512, 512, 1, 16, 0x300000, 0x307000, 0xfffffa00, true);
|
||||
break;
|
||||
case 0x329973a0 :
|
||||
_family = FAMILY_SAM9XE;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM9XE128", 0x200000, 256, 512, 1, 8, 0x300000, 0x303000, 0xfffffa00, true);
|
||||
break;
|
||||
//
|
||||
// SAM4E
|
||||
//
|
||||
case 0x23cc0ce0:
|
||||
switch (extChipId)
|
||||
{
|
||||
case 0x00120200: // E
|
||||
case 0x00120201: // C
|
||||
_family = FAMILY_SAM4E;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM4E16", 0x400000, 2048, 512, 1, 128, 0x20001000, 0x20020000, 0x400e0a00, false);
|
||||
break;
|
||||
case 0x00120208: // E
|
||||
case 0x00120209: // C
|
||||
_family = FAMILY_SAM4E;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAM4E8", 0x400000, 1024, 512, 1, 64, 0x20001000, 0x20020000, 0x400e0a00, false);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
//
|
||||
// SAME70
|
||||
//
|
||||
case 0x210d0a00:
|
||||
_family = FAMILY_SAME70;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAME70x19", 0x400000, 1024, 512, 1, 32, 0x20401000, 0x20404000, 0x400e0c00, false);
|
||||
break;
|
||||
case 0x21020c00:
|
||||
_family = FAMILY_SAME70;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAME70x20", 0x400000, 2048, 512, 1, 64, 0x20401000, 0x20404000, 0x400e0c00, false);
|
||||
break;
|
||||
case 0x21020e00:
|
||||
_family = FAMILY_SAME70;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAME70x21", 0x400000, 4096, 512, 1, 128, 0x20401000, 0x20404000, 0x400e0c00, false);
|
||||
break;
|
||||
//
|
||||
// SAMS70
|
||||
//
|
||||
case 0x211d0a00:
|
||||
_family = FAMILY_SAMS70;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAMS70x19", 0x400000, 1024, 512, 1, 32, 0x20401000, 0x20404000, 0x400e0c00, false);
|
||||
break;
|
||||
case 0x21120c00:
|
||||
_family = FAMILY_SAMS70;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAMS70x20", 0x400000, 2048, 512, 1, 64, 0x20401000, 0x20404000, 0x400e0c00, false);
|
||||
break;
|
||||
case 0x21120e00:
|
||||
_family = FAMILY_SAMS70;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAMS70x21", 0x400000, 4096, 512, 1, 128, 0x20401000, 0x20404000, 0x400e0c00, false);
|
||||
break;
|
||||
//
|
||||
// SAMV70
|
||||
//
|
||||
case 0x213d0a00:
|
||||
_family = FAMILY_SAMV70;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAMV70x19", 0x400000, 1024, 512, 1, 32, 0x20401000, 0x20404000, 0x400e0c00, false);
|
||||
break;
|
||||
case 0x21320c00:
|
||||
_family = FAMILY_SAMV70;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAMV70x20", 0x400000, 2048, 512, 1, 64, 0x20401000, 0x20404000, 0x400e0c00, false);
|
||||
break;
|
||||
//
|
||||
// SAMV71
|
||||
//
|
||||
case 0x212d0a00:
|
||||
_family = FAMILY_SAMV71;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAMV71x19", 0x400000, 1024, 512, 1, 32, 0x20401000, 0x20404000, 0x400e0c00, false);
|
||||
break;
|
||||
case 0x21220c00:
|
||||
_family = FAMILY_SAMV71;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAMV71x20", 0x400000, 2048, 512, 1, 64, 0x20401000, 0x20404000, 0x400e0c00, false);
|
||||
break;
|
||||
case 0x21220e00:
|
||||
_family = FAMILY_SAMV71;
|
||||
flashPtr = new EefcFlash(_samba, "ATSAMV71x21", 0x400000, 4096, 512, 1, 128, 0x20401000, 0x20404000, 0x400e0c00, false);
|
||||
break;
|
||||
//
|
||||
// No CHIPID devices
|
||||
//
|
||||
case 0:
|
||||
switch (deviceId & 0xffff00ff)
|
||||
{
|
||||
//
|
||||
// SAMD21
|
||||
//
|
||||
case 0x10010003: // J15A
|
||||
case 0x10010008: // G15A
|
||||
case 0x1001000d: // E15A
|
||||
case 0x10010021: // J15B
|
||||
case 0x10010024: // G15B
|
||||
case 0x10010027: // E15B
|
||||
case 0x10010056: // E15B WLCSP
|
||||
case 0x10010063: // E15C WLCSP
|
||||
_family = FAMILY_SAMD21;
|
||||
flashPtr = new D2xNvmFlash(_samba, "ATSAMD21x15", 512, 64, 0x20000800, 0x20001000) ;
|
||||
break;
|
||||
|
||||
case 0x10010002: // J16A
|
||||
case 0x10010007: // G16A
|
||||
case 0x1001000c: // E16A
|
||||
case 0x10010020: // J16B
|
||||
case 0x10010023: // G16B
|
||||
case 0x10010026: // E16B
|
||||
case 0x10010055: // E16B WLCSP
|
||||
case 0x10010062: // E16C WLCSP
|
||||
_family = FAMILY_SAMD21;
|
||||
flashPtr = new D2xNvmFlash(_samba, "ATSAMD21x16", 1024, 64, 0x20001000, 0x20002000) ;
|
||||
break;
|
||||
|
||||
case 0x10010001: // J17A
|
||||
case 0x10010006: // G17A
|
||||
case 0x1001000b: // E17A
|
||||
case 0x10010010: // G17A WLCSP
|
||||
_family = FAMILY_SAMD21;
|
||||
flashPtr = new D2xNvmFlash(_samba, "ATSAMD21x17", 2048, 64, 0x20002000, 0x20004000) ;
|
||||
break;
|
||||
|
||||
case 0x10010000: // J18A
|
||||
case 0x10010005: // G18A
|
||||
case 0x1001000a: // E18A
|
||||
case 0x1001000f: // G18A WLCSP
|
||||
_family = FAMILY_SAMD21;
|
||||
flashPtr = new D2xNvmFlash(_samba, "ATSAMD21x18", 4096, 64, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
//
|
||||
// SAMR21
|
||||
//
|
||||
case 0x1001001e: // E16A
|
||||
case 0x1001001b: // G16A
|
||||
_family = FAMILY_SAMR21;
|
||||
flashPtr = new D2xNvmFlash(_samba, "ATSAMR21x16", 1024, 64, 0x20001000, 0x20002000) ;
|
||||
break;
|
||||
|
||||
case 0x1001001d: // E17A
|
||||
case 0x1001001a: // G17A
|
||||
_family = FAMILY_SAMR21;
|
||||
flashPtr = new D2xNvmFlash(_samba, "ATSAMR21x17", 2048, 64, 0x20002000, 0x20004000) ;
|
||||
break;
|
||||
|
||||
case 0x1001001c: // E18A
|
||||
case 0x10010019: // G18A
|
||||
_family = FAMILY_SAMR21;
|
||||
flashPtr = new D2xNvmFlash(_samba, "ATSAMR21x18", 4096, 64, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
case 0x10010018: // E19A
|
||||
_family = FAMILY_SAMR21;
|
||||
flashPtr = new D2xNvmFlash(_samba, "ATSAMR21x19", 4096, 64, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
//
|
||||
// SAML21
|
||||
//
|
||||
case 0x1081000d: // E15A
|
||||
case 0x1081001c: // E15B
|
||||
_family = FAMILY_SAMD21;
|
||||
flashPtr = new D2xNvmFlash(_samba, "ATSAML21x15", 512, 64, 0x20000800, 0x20001000) ;
|
||||
break;
|
||||
|
||||
case 0x10810002: // J16A
|
||||
case 0x10810007: // G16A
|
||||
case 0x1081000c: // E16A
|
||||
case 0x10810011: // J16B
|
||||
case 0x10810016: // G16B
|
||||
case 0x1081001b: // E16B
|
||||
_family = FAMILY_SAML21;
|
||||
flashPtr = new D2xNvmFlash(_samba, "ATSAML21x16", 1024, 64, 0x20001000, 0x20002000) ;
|
||||
break;
|
||||
|
||||
case 0x10810001: // J17A
|
||||
case 0x10810006: // G17A
|
||||
case 0x1081000b: // E17A
|
||||
case 0x10810010: // J17B
|
||||
case 0x10810015: // G17B
|
||||
case 0x1081001a: // E17B
|
||||
_family = FAMILY_SAML21;
|
||||
flashPtr = new D2xNvmFlash(_samba, "ATSAML21x17", 2048, 64, 0x20002000, 0x20004000) ;
|
||||
break;
|
||||
|
||||
case 0x10810000: // J18A
|
||||
case 0x10810005: // G18A
|
||||
case 0x1081000a: // E18A
|
||||
case 0x1081000f: // J18B
|
||||
case 0x10810014: // G18B
|
||||
case 0x10810019: // E18B
|
||||
_family = FAMILY_SAML21;
|
||||
flashPtr = new D2xNvmFlash(_samba, "ATSAML21x18", 4096, 64, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
//
|
||||
// SAMD51
|
||||
//
|
||||
case 0x60060006: // J18A
|
||||
case 0x60060008: // G18A
|
||||
_family = FAMILY_SAMD51;
|
||||
flashPtr = new D5xNvmFlash(_samba, "ATSAMD51x18", 512, 512, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
case 0x60060001: // P19A
|
||||
case 0x60060003: // N19A
|
||||
case 0x60060005: // J19A
|
||||
case 0x60060007: // G19A
|
||||
_family = FAMILY_SAMD51;
|
||||
flashPtr = new D5xNvmFlash(_samba, "ATSAMD51x19", 1024, 512, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
case 0x60060000: // P20A
|
||||
case 0x60060002: // N20A
|
||||
case 0x60060004: // J20A
|
||||
_family = FAMILY_SAMD51;
|
||||
flashPtr = new D5xNvmFlash(_samba, "ATSAMD51x20", 2048, 512, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
//
|
||||
// SAME51
|
||||
//
|
||||
case 0x61810003: // J18A
|
||||
_family = FAMILY_SAME51;
|
||||
flashPtr = new D5xNvmFlash(_samba, "ATSAME51x18", 512, 512, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
case 0x61810002: // J19A
|
||||
case 0x61810001: // N19A
|
||||
_family = FAMILY_SAME51;
|
||||
flashPtr = new D5xNvmFlash(_samba, "ATSAME51x19", 1024, 512, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
case 0x61810004: // J20A
|
||||
case 0x61810000: // N20A
|
||||
_family = FAMILY_SAME51;
|
||||
flashPtr = new D5xNvmFlash(_samba, "ATSAME51x20", 2048, 512, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
//
|
||||
// SAME53
|
||||
//
|
||||
case 0x61830006: // J18A
|
||||
_family = FAMILY_SAME53;
|
||||
flashPtr = new D5xNvmFlash(_samba, "ATSAME53x18", 512, 512, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
case 0x61830005: // J19A
|
||||
case 0x61830003: // N19A
|
||||
_family = FAMILY_SAME53;
|
||||
flashPtr = new D5xNvmFlash(_samba, "ATSAME53x19", 1024, 512, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
case 0x61830004: // J20A
|
||||
case 0x61830002: // N20A
|
||||
_family = FAMILY_SAME53;
|
||||
flashPtr = new D5xNvmFlash(_samba, "ATSAME53x20", 2048, 512, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
//
|
||||
// SAME54
|
||||
//
|
||||
case 0x61840001: // P19A
|
||||
case 0x61840003: // N19A
|
||||
_family = FAMILY_SAME54;
|
||||
flashPtr = new D5xNvmFlash(_samba, "ATSAME54x19", 1024, 512, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
case 0x61840000: // P20A
|
||||
case 0x61840002: // N20A
|
||||
_family = FAMILY_SAME54;
|
||||
flashPtr = new D5xNvmFlash(_samba, "ATSAME54x20", 2048, 512, 0x20004000, 0x20008000) ;
|
||||
break;
|
||||
|
||||
//
|
||||
// Unknown
|
||||
//
|
||||
default:
|
||||
throw DeviceUnsupportedError();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
//
|
||||
// Unsupported device
|
||||
//
|
||||
default:
|
||||
throw DeviceUnsupportedError();
|
||||
break;
|
||||
}
|
||||
|
||||
_flash = std::unique_ptr<Flash>(flashPtr);
|
||||
}
|
||||
|
||||
void
|
||||
Device::reset()
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (_family)
|
||||
{
|
||||
case FAMILY_SAMD21:
|
||||
case FAMILY_SAMR21:
|
||||
case FAMILY_SAML21:
|
||||
case FAMILY_SAMD51:
|
||||
case FAMILY_SAME51:
|
||||
case FAMILY_SAME53:
|
||||
case FAMILY_SAME54:
|
||||
case FAMILY_SAME70:
|
||||
case FAMILY_SAMS70:
|
||||
case FAMILY_SAMV70:
|
||||
case FAMILY_SAMV71:
|
||||
_samba.writeWord(0xE000ED0C, 0x05FA0004);
|
||||
break;
|
||||
|
||||
case FAMILY_SAM3X:
|
||||
case FAMILY_SAM3S:
|
||||
case FAMILY_SAM3A:
|
||||
_samba.writeWord(0x400E1A00, 0xA500000D);
|
||||
break;
|
||||
|
||||
case FAMILY_SAM3U:
|
||||
_samba.writeWord(0x400E1200, 0xA500000D);
|
||||
break;
|
||||
|
||||
case FAMILY_SAM3N:
|
||||
case FAMILY_SAM4S:
|
||||
_samba.writeWord(0x400E1400, 0xA500000D);
|
||||
break;
|
||||
|
||||
case FAMILY_SAM4E:
|
||||
_samba.writeWord(0x400E1800, 0xA500000D);
|
||||
break;
|
||||
|
||||
case FAMILY_SAM7S:
|
||||
case FAMILY_SAM7SE:
|
||||
case FAMILY_SAM7X:
|
||||
case FAMILY_SAM7XC:
|
||||
case FAMILY_SAM7L:
|
||||
case FAMILY_SAM9XE:
|
||||
_samba.writeWord(0xFFFFFD00, 0xA500000D);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (std::exception& expected)
|
||||
{ // writeWord will most likely throw an exception when the CPU is reset
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _DEVICE_H
|
||||
#define _DEVICE_H
|
||||
|
||||
#include <exception>
|
||||
|
||||
#include "Samba.h"
|
||||
#include "Flash.h"
|
||||
|
||||
class DeviceUnsupportedError : public std::exception
|
||||
{
|
||||
public:
|
||||
DeviceUnsupportedError() : exception() {};
|
||||
const char* what() const throw() { return "Device unsupported"; }
|
||||
};
|
||||
|
||||
class Device
|
||||
{
|
||||
public:
|
||||
enum Family {
|
||||
FAMILY_NONE,
|
||||
|
||||
FAMILY_SAM7S,
|
||||
FAMILY_SAM7SE,
|
||||
FAMILY_SAM7X,
|
||||
FAMILY_SAM7XC,
|
||||
FAMILY_SAM7L,
|
||||
|
||||
FAMILY_SAM3N,
|
||||
FAMILY_SAM3S,
|
||||
FAMILY_SAM3U,
|
||||
FAMILY_SAM3X,
|
||||
FAMILY_SAM3A,
|
||||
|
||||
FAMILY_SAM4S,
|
||||
FAMILY_SAM4E,
|
||||
|
||||
FAMILY_SAM9XE,
|
||||
|
||||
FAMILY_SAMD21,
|
||||
FAMILY_SAMR21,
|
||||
FAMILY_SAML21,
|
||||
|
||||
FAMILY_SAMD51,
|
||||
FAMILY_SAME51,
|
||||
FAMILY_SAME53,
|
||||
FAMILY_SAME54,
|
||||
|
||||
FAMILY_SAME70,
|
||||
FAMILY_SAMS70,
|
||||
FAMILY_SAMV70,
|
||||
FAMILY_SAMV71,
|
||||
};
|
||||
|
||||
Device(Samba& samba) : _samba(samba), _flash(nullptr), _family(FAMILY_NONE) {}
|
||||
virtual ~Device() {}
|
||||
|
||||
void create();
|
||||
|
||||
Family getFamily() { return _family; }
|
||||
|
||||
typedef std::unique_ptr<Flash> const FlashPtr;
|
||||
|
||||
FlashPtr& getFlash() { return _flash; }
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
Samba& _samba;
|
||||
std::unique_ptr<Flash> _flash;
|
||||
Family _family;
|
||||
|
||||
void readChipId(uint32_t& chipId, uint32_t& extChipId);
|
||||
};
|
||||
|
||||
#endif // _DEVICE_H
|
||||
|
|
@ -0,0 +1,363 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "EefcFlash.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define EEFC_KEY 0x5a
|
||||
|
||||
#define EEFC0_FMR (_regs + 0x00)
|
||||
#define EEFC0_FCR (_regs + 0x04)
|
||||
#define EEFC0_FSR (_regs + 0x08)
|
||||
#define EEFC0_FRR (_regs + 0x0C)
|
||||
|
||||
#define EEFC1_FMR (_regs + 0x200)
|
||||
#define EEFC1_FCR (_regs + 0x204)
|
||||
#define EEFC1_FSR (_regs + 0x208)
|
||||
#define EEFC1_FRR (_regs + 0x20C)
|
||||
|
||||
#define EEFC_FCMD_GETD 0x0
|
||||
#define EEFC_FCMD_WP 0x1
|
||||
#define EEFC_FCMD_WPL 0x2
|
||||
#define EEFC_FCMD_EWP 0x3
|
||||
#define EEFC_FCMD_EWPL 0x4
|
||||
#define EEFC_FCMD_EA 0x5
|
||||
#define EEFC_FCMD_EPA 0x7
|
||||
#define EEFC_FCMD_SLB 0x8
|
||||
#define EEFC_FCMD_CLB 0x9
|
||||
#define EEFC_FCMD_GLB 0xa
|
||||
#define EEFC_FCMD_SGPB 0xb
|
||||
#define EEFC_FCMD_CGPB 0xc
|
||||
#define EEFC_FCMD_GGPB 0xd
|
||||
|
||||
const uint32_t
|
||||
EefcFlash::PagesPerErase = 8;
|
||||
|
||||
EefcFlash::EefcFlash(Samba& samba,
|
||||
const std::string& name,
|
||||
uint32_t addr,
|
||||
uint32_t pages,
|
||||
uint32_t size,
|
||||
uint32_t planes,
|
||||
uint32_t lockRegions,
|
||||
uint32_t user,
|
||||
uint32_t stack,
|
||||
uint32_t regs,
|
||||
bool canBrownout)
|
||||
: Flash(samba, name, addr, pages, size, planes, lockRegions, user, stack),
|
||||
_regs(regs), _canBrownout(canBrownout), _eraseAuto(true)
|
||||
{
|
||||
assert(planes == 1 || planes == 2);
|
||||
assert(pages <= 4096);
|
||||
assert(lockRegions <= 256);
|
||||
|
||||
// SAM3 Errata (FWS must be 6)
|
||||
_samba.writeWord(EEFC0_FMR, 0x6 << 8);
|
||||
if (planes == 2)
|
||||
_samba.writeWord(EEFC1_FMR, 0x6 << 8);
|
||||
}
|
||||
|
||||
EefcFlash::~EefcFlash()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
EefcFlash::eraseAll(uint32_t offset)
|
||||
{
|
||||
// Do a full chip erase if the offset is 0
|
||||
if (offset == 0)
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR0(EEFC_FCMD_EA, 0);
|
||||
if (_planes == 2)
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR1(EEFC_FCMD_EA, 0);
|
||||
}
|
||||
|
||||
// Erase all can take an exceptionally long time on some devices
|
||||
// so wait on FSR for up to 30 seconds
|
||||
waitFSR(30);
|
||||
}
|
||||
// Else we must do it by pages
|
||||
else
|
||||
{
|
||||
// Offset must be on an erase page boundary
|
||||
if (offset % (_size * PagesPerErase))
|
||||
throw FlashEraseError();
|
||||
|
||||
// Erase each PagesPerErase set of pages
|
||||
for (uint32_t pageNum = offset / _size; pageNum < _pages; pageNum += PagesPerErase)
|
||||
{
|
||||
if (_planes == 1 || pageNum < _pages / 2)
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR0(EEFC_FCMD_EPA, pageNum | 0x1);
|
||||
}
|
||||
else
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR1(EEFC_FCMD_EPA, (pageNum % (_pages / 2)) | 0x1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EefcFlash::eraseAuto(bool enable)
|
||||
{
|
||||
_eraseAuto = enable;
|
||||
}
|
||||
|
||||
std::vector<bool>
|
||||
EefcFlash::getLockRegions()
|
||||
{
|
||||
std::vector<bool> regions(_lockRegions);
|
||||
uint32_t frr;
|
||||
uint32_t bit;
|
||||
|
||||
waitFSR();
|
||||
for (uint32_t region = 0; region < _lockRegions; region++)
|
||||
{
|
||||
if (_planes == 2 && region >= _lockRegions / 2)
|
||||
{
|
||||
bit = region - _lockRegions / 2;
|
||||
writeFCR1(EEFC_FCMD_GLB, 0);
|
||||
waitFSR();
|
||||
frr = readFRR1();
|
||||
while (bit >= 32)
|
||||
{
|
||||
frr = readFRR1();
|
||||
bit -= 32;
|
||||
}
|
||||
regions[region] = (frr & (1 << bit)) != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
bit = region;
|
||||
writeFCR0(EEFC_FCMD_GLB, 0);
|
||||
waitFSR();
|
||||
frr = readFRR0();
|
||||
while (bit >= 32)
|
||||
{
|
||||
frr = readFRR0();
|
||||
bit -= 32;
|
||||
}
|
||||
regions[region] = (frr & (1 << bit)) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
return regions;
|
||||
}
|
||||
|
||||
bool
|
||||
EefcFlash::getSecurity()
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR0(EEFC_FCMD_GGPB, 0);
|
||||
waitFSR();
|
||||
return (readFRR0() & (1 << 0));
|
||||
}
|
||||
|
||||
bool
|
||||
EefcFlash::getBod()
|
||||
{
|
||||
if (!_canBrownout)
|
||||
return false;
|
||||
|
||||
waitFSR();
|
||||
writeFCR0(EEFC_FCMD_GGPB, 0);
|
||||
waitFSR();
|
||||
return (readFRR0() & (1 << 1));
|
||||
}
|
||||
|
||||
bool
|
||||
EefcFlash::getBor()
|
||||
{
|
||||
if (!_canBrownout)
|
||||
return false;
|
||||
|
||||
waitFSR();
|
||||
writeFCR0(EEFC_FCMD_GGPB, 0);
|
||||
waitFSR();
|
||||
return (readFRR0() & (1 << 2));
|
||||
}
|
||||
|
||||
bool
|
||||
EefcFlash::getBootFlash()
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR0(EEFC_FCMD_GGPB, 0);
|
||||
waitFSR();
|
||||
return (readFRR0() & (1 << (_canBrownout ? 3 : 1)));
|
||||
}
|
||||
|
||||
void
|
||||
EefcFlash::writeOptions()
|
||||
{
|
||||
if (canBootFlash() && _bootFlash.isDirty() && _bootFlash.get() != getBootFlash())
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR0(_bootFlash.get() ? EEFC_FCMD_SGPB : EEFC_FCMD_CGPB, (canBod() ? 3 : 1));
|
||||
}
|
||||
if (canBor() && _bor.isDirty() && _bor.get() != getBor())
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR0(_bor.get() ? EEFC_FCMD_SGPB : EEFC_FCMD_CGPB, 2);
|
||||
}
|
||||
if (canBod() && _bod.isDirty() && _bod.get() != getBod())
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR0(_bod.get() ? EEFC_FCMD_SGPB : EEFC_FCMD_CGPB, 1);
|
||||
}
|
||||
if (_regions.isDirty())
|
||||
{
|
||||
uint32_t page;
|
||||
std::vector<bool> current;
|
||||
|
||||
if (_regions.get().size() >= _lockRegions)
|
||||
throw FlashRegionError();
|
||||
|
||||
current = getLockRegions();
|
||||
|
||||
for (uint32_t region = 0; region < _lockRegions; region++)
|
||||
{
|
||||
if (_regions.get()[region] != current[region])
|
||||
{
|
||||
if (_planes == 2 && region >= _lockRegions / 2)
|
||||
{
|
||||
page = (region - _lockRegions / 2) * _pages / _lockRegions;
|
||||
waitFSR();
|
||||
writeFCR1(_regions.get()[region] ? EEFC_FCMD_SLB : EEFC_FCMD_CLB, page);
|
||||
}
|
||||
else
|
||||
{
|
||||
page = region * _pages / _lockRegions;
|
||||
waitFSR();
|
||||
writeFCR0(_regions.get()[region] ? EEFC_FCMD_SLB : EEFC_FCMD_CLB, page);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_security.isDirty() && _security.get() == true && _security.get() != getSecurity())
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR0(EEFC_FCMD_SGPB, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EefcFlash::writePage(uint32_t page)
|
||||
{
|
||||
if (page >= _pages)
|
||||
throw FlashPageError();
|
||||
|
||||
_wordCopy.setDstAddr(_addr + page * _size);
|
||||
_wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB);
|
||||
_onBufferA = !_onBufferA;
|
||||
waitFSR();
|
||||
_wordCopy.runv();
|
||||
if (_planes == 2 && page >= _pages / 2)
|
||||
writeFCR1(_eraseAuto ? EEFC_FCMD_EWP : EEFC_FCMD_WP, page - _pages / 2);
|
||||
else
|
||||
writeFCR0(_eraseAuto ? EEFC_FCMD_EWP : EEFC_FCMD_WP, page);
|
||||
}
|
||||
|
||||
void
|
||||
EefcFlash::readPage(uint32_t page, uint8_t* data)
|
||||
{
|
||||
if (page >= _pages)
|
||||
throw FlashPageError();
|
||||
|
||||
// The SAM3 firmware has a bug where it returns all zeros for reads
|
||||
// directly from the flash so instead, we copy the flash page to
|
||||
// SRAM and read it from there.
|
||||
_wordCopy.setDstAddr(_onBufferA ? _pageBufferA : _pageBufferB);
|
||||
_wordCopy.setSrcAddr(_addr + page * _size);
|
||||
waitFSR();
|
||||
_wordCopy.runv();
|
||||
_samba.read(_onBufferA ? _pageBufferA : _pageBufferB, data, _size);
|
||||
}
|
||||
|
||||
void
|
||||
EefcFlash::waitFSR(int seconds)
|
||||
{
|
||||
int tries = seconds * 1000;
|
||||
uint32_t fsr0;
|
||||
uint32_t fsr1 = 0x1;
|
||||
|
||||
while (tries-- > 0)
|
||||
{
|
||||
fsr0 = _samba.readWord(EEFC0_FSR);
|
||||
if (fsr0 & 0x2)
|
||||
throw FlashCmdError();
|
||||
if (fsr0 & 0x4)
|
||||
throw FlashLockError();
|
||||
|
||||
if (_planes == 2)
|
||||
{
|
||||
fsr1 = _samba.readWord(EEFC1_FSR);
|
||||
if (fsr1 & 0x2)
|
||||
throw FlashCmdError();
|
||||
if (fsr1 & 0x4)
|
||||
throw FlashLockError();
|
||||
}
|
||||
if (fsr0 & fsr1 & 0x1)
|
||||
break;
|
||||
usleep(1000);
|
||||
}
|
||||
if (tries == 0)
|
||||
throw FlashTimeoutError();
|
||||
}
|
||||
|
||||
void
|
||||
EefcFlash::writeFCR0(uint8_t cmd, uint32_t arg)
|
||||
{
|
||||
_samba.writeWord(EEFC0_FCR, (EEFC_KEY << 24) | (arg << 8) | cmd);
|
||||
}
|
||||
|
||||
void
|
||||
EefcFlash::writeFCR1(uint8_t cmd, uint32_t arg)
|
||||
{
|
||||
_samba.writeWord(EEFC1_FCR, (EEFC_KEY << 24) | (arg << 8) | cmd);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EefcFlash::readFRR0()
|
||||
{
|
||||
return _samba.readWord(EEFC0_FRR);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EefcFlash::readFRR1()
|
||||
{
|
||||
return _samba.readWord(EEFC1_FRR);
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _EEFCFLASH_H
|
||||
#define _EEFCFLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <exception>
|
||||
|
||||
#include "Flash.h"
|
||||
|
||||
class EefcFlash : public Flash
|
||||
{
|
||||
public:
|
||||
EefcFlash(Samba& samba,
|
||||
const std::string& name,
|
||||
uint32_t addr,
|
||||
uint32_t pages,
|
||||
uint32_t size,
|
||||
uint32_t planes,
|
||||
uint32_t lockRegions,
|
||||
uint32_t user,
|
||||
uint32_t stack,
|
||||
uint32_t regs,
|
||||
bool canBrownout);
|
||||
virtual ~EefcFlash();
|
||||
|
||||
void eraseAll(uint32_t offset);
|
||||
void eraseAuto(bool enable);
|
||||
|
||||
std::vector<bool> getLockRegions();
|
||||
|
||||
bool getSecurity();
|
||||
|
||||
bool getBod();
|
||||
bool canBod() { return _canBrownout; }
|
||||
|
||||
bool getBor();
|
||||
bool canBor() { return _canBrownout; }
|
||||
|
||||
bool getBootFlash();
|
||||
bool canBootFlash() { return true; }
|
||||
|
||||
void writeOptions();
|
||||
|
||||
void writePage(uint32_t page);
|
||||
void readPage(uint32_t page, uint8_t* data);
|
||||
|
||||
static const uint32_t PagesPerErase;
|
||||
|
||||
private:
|
||||
uint32_t _regs;
|
||||
bool _canBrownout;
|
||||
bool _eraseAuto;
|
||||
|
||||
void waitFSR(int seconds = 1);
|
||||
void writeFCR0(uint8_t cmd, uint32_t arg);
|
||||
void writeFCR1(uint8_t cmd, uint32_t arg);
|
||||
uint32_t readFRR0();
|
||||
uint32_t readFRR1();
|
||||
};
|
||||
|
||||
#endif // _EEFCFLASH_H
|
|
@ -0,0 +1,295 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "EfcFlash.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define EFC_KEY 0x5a
|
||||
|
||||
#define EFC0_FMR 0xffffff60
|
||||
#define EFC0_FCR 0xffffff64
|
||||
#define EFC0_FSR 0xffffff68
|
||||
|
||||
#define EFC1_FMR 0xffffff70
|
||||
#define EFC1_FCR 0xffffff74
|
||||
#define EFC1_FSR 0xffffff78
|
||||
|
||||
#define EFC_FCMD_WP 0x1
|
||||
#define EFC_FCMD_SLB 0x2
|
||||
#define EFC_FCMD_WPL 0x3
|
||||
#define EFC_FCMD_CLB 0x4
|
||||
#define EFC_FCMD_EA 0x8
|
||||
#define EFC_FCMD_SGPB 0xb
|
||||
#define EFC_FCMD_CGPB 0xd
|
||||
#define EFC_FCMD_SSB 0xf
|
||||
|
||||
EfcFlash::EfcFlash(Samba& samba,
|
||||
const std::string& name,
|
||||
uint32_t addr,
|
||||
uint32_t pages,
|
||||
uint32_t size,
|
||||
uint32_t planes,
|
||||
uint32_t lockRegions,
|
||||
uint32_t user,
|
||||
uint32_t stack,
|
||||
bool canBootFlash)
|
||||
: Flash(samba, name, addr, pages, size, planes, lockRegions, user, stack),
|
||||
_canBootFlash(canBootFlash)
|
||||
{
|
||||
assert(planes == 1 || planes == 2);
|
||||
assert(pages <= planes * 1024);
|
||||
assert(lockRegions <= 32);
|
||||
|
||||
eraseAuto(true);
|
||||
}
|
||||
|
||||
EfcFlash::~EfcFlash()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
EfcFlash::eraseAll(uint32_t offset)
|
||||
{
|
||||
if (offset != 0)
|
||||
throw FlashEraseError();
|
||||
|
||||
waitFSR();
|
||||
writeFCR0(EFC_FCMD_EA, 0);
|
||||
if (_planes == 2)
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR0(EFC_FCMD_EA, _pages / 2);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EfcFlash::eraseAuto(bool enable)
|
||||
{
|
||||
uint32_t fmr;
|
||||
|
||||
waitFSR();
|
||||
fmr = _samba.readWord(EFC0_FMR);
|
||||
if (enable)
|
||||
fmr &= ~(1 << 7);
|
||||
else
|
||||
fmr |= (1 << 7);
|
||||
|
||||
_samba.writeWord(EFC0_FMR, fmr);
|
||||
if (_planes == 2)
|
||||
{
|
||||
waitFSR();
|
||||
_samba.writeWord(EFC1_FMR, fmr);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<bool>
|
||||
EfcFlash::getLockRegions()
|
||||
{
|
||||
std::vector<bool> regions(_lockRegions);
|
||||
uint32_t fsr0;
|
||||
uint32_t fsr1;
|
||||
|
||||
fsr0 = readFSR0();
|
||||
if (_planes == 2)
|
||||
fsr1 = readFSR1();
|
||||
else
|
||||
fsr1 = 0;
|
||||
|
||||
for (uint32_t region = 0; region < _lockRegions; region++)
|
||||
{
|
||||
if (_planes == 2 && region >= _lockRegions / 2)
|
||||
regions[region] = (fsr1 & (1 << (16 + region - _lockRegions / 2))) != 0;
|
||||
else
|
||||
regions[region] = (fsr0 & (1 << (16 + region))) != 0;
|
||||
}
|
||||
|
||||
return regions;
|
||||
}
|
||||
|
||||
bool
|
||||
EfcFlash::getSecurity()
|
||||
{
|
||||
return (readFSR0() & (1 << 4));
|
||||
}
|
||||
|
||||
bool
|
||||
EfcFlash::getBod()
|
||||
{
|
||||
return (readFSR0() & (1 << 8));
|
||||
}
|
||||
|
||||
bool
|
||||
EfcFlash::getBor()
|
||||
{
|
||||
return (readFSR0() & (2 << 8));
|
||||
}
|
||||
|
||||
bool
|
||||
EfcFlash::getBootFlash()
|
||||
{
|
||||
if (!_canBootFlash)
|
||||
return false;
|
||||
|
||||
return (readFSR0() & (1 << 10));
|
||||
}
|
||||
|
||||
void
|
||||
EfcFlash::writeOptions()
|
||||
{
|
||||
if (canBootFlash() && _bootFlash.isDirty() && _bootFlash.get() != getBootFlash())
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR0(_bootFlash.get() ? EFC_FCMD_SGPB : EFC_FCMD_CGPB, 2);
|
||||
}
|
||||
if (canBor() && _bor.isDirty() && _bor.get() != getBor())
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR0(_bor.get() ? EFC_FCMD_SGPB : EFC_FCMD_CGPB, 1);
|
||||
}
|
||||
if (canBod() && _bod.isDirty() && _bod.get() != getBod())
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR0(_bod.get() ? EFC_FCMD_SGPB : EFC_FCMD_CGPB, 0);
|
||||
}
|
||||
if (_regions.isDirty())
|
||||
{
|
||||
uint32_t page;
|
||||
std::vector<bool> current;
|
||||
|
||||
current = getLockRegions();
|
||||
|
||||
for (uint32_t region = 0; region < _regions.get().size(); region++)
|
||||
{
|
||||
if (_regions.get()[region] != current[region])
|
||||
{
|
||||
if (_planes == 2 && region >= _lockRegions / 2)
|
||||
{
|
||||
page = (region - _lockRegions / 2) * _pages / _lockRegions;
|
||||
waitFSR();
|
||||
writeFCR1(_regions.get()[region] ? EFC_FCMD_SLB : EFC_FCMD_CLB, page);
|
||||
}
|
||||
else
|
||||
{
|
||||
page = region * _pages / _lockRegions;
|
||||
waitFSR();
|
||||
writeFCR0(_regions.get()[region] ? EFC_FCMD_SLB : EFC_FCMD_CLB, page);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_security.isDirty() && _security.get() == true && _security.get() != getSecurity())
|
||||
{
|
||||
waitFSR();
|
||||
writeFCR0(EFC_FCMD_SSB, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EfcFlash::writePage(uint32_t page)
|
||||
{
|
||||
if (page >= _pages)
|
||||
throw FlashPageError();
|
||||
|
||||
_wordCopy.setDstAddr(_addr + page * _size);
|
||||
_wordCopy.setSrcAddr(_onBufferA ? _pageBufferA : _pageBufferB);
|
||||
_onBufferA = !_onBufferA;
|
||||
waitFSR();
|
||||
_wordCopy.run();
|
||||
if (_planes == 2 && page >= _pages / 2)
|
||||
writeFCR1(EFC_FCMD_WP, page - _pages / 2);
|
||||
else
|
||||
writeFCR0(EFC_FCMD_WP, page);
|
||||
}
|
||||
|
||||
void
|
||||
EfcFlash::readPage(uint32_t page, uint8_t* data)
|
||||
{
|
||||
if (page >= _pages)
|
||||
throw FlashPageError();
|
||||
|
||||
waitFSR();
|
||||
_samba.read(_addr + page * _size, data, _size);
|
||||
}
|
||||
|
||||
void
|
||||
EfcFlash::waitFSR(int seconds)
|
||||
{
|
||||
int tries = seconds * 1000;
|
||||
uint32_t fsr0;
|
||||
uint32_t fsr1 = 0x1;
|
||||
|
||||
while (tries-- > 0)
|
||||
{
|
||||
fsr0 = readFSR0();
|
||||
if (fsr0 & 0x2)
|
||||
throw FlashCmdError();
|
||||
if (fsr0 & 0x4)
|
||||
throw FlashLockError();
|
||||
|
||||
if (_planes == 2)
|
||||
{
|
||||
fsr1 = readFSR1();
|
||||
if (fsr1 & 0x2)
|
||||
throw FlashCmdError();
|
||||
if (fsr1 & 0x4)
|
||||
throw FlashLockError();
|
||||
}
|
||||
if (fsr0 & fsr1 & 0x1)
|
||||
break;
|
||||
usleep(1000);
|
||||
}
|
||||
if (tries == 0)
|
||||
throw FlashTimeoutError();
|
||||
}
|
||||
|
||||
void
|
||||
EfcFlash::writeFCR0(uint8_t cmd, uint32_t arg)
|
||||
{
|
||||
_samba.writeWord(EFC0_FCR, (EFC_KEY << 24) | (arg << 8) | cmd);
|
||||
}
|
||||
|
||||
void
|
||||
EfcFlash::writeFCR1(uint8_t cmd, uint32_t arg)
|
||||
{
|
||||
_samba.writeWord(EFC1_FCR, (EFC_KEY << 24) | (arg << 8) | cmd);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EfcFlash::readFSR0()
|
||||
{
|
||||
return _samba.readWord(EFC0_FSR);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
EfcFlash::readFSR1()
|
||||
{
|
||||
return _samba.readWord(EFC1_FSR);
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _EFCFLASH_H
|
||||
#define _EFCFLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <exception>
|
||||
|
||||
#include "Flash.h"
|
||||
|
||||
class EfcFlash : public Flash
|
||||
{
|
||||
public:
|
||||
EfcFlash(Samba& samba,
|
||||
const std::string& name,
|
||||
uint32_t addr,
|
||||
uint32_t pages,
|
||||
uint32_t size,
|
||||
uint32_t planes,
|
||||
uint32_t lockRegions,
|
||||
uint32_t user,
|
||||
uint32_t stack,
|
||||
bool canBootFlash);
|
||||
virtual ~EfcFlash();
|
||||
|
||||
void eraseAll(uint32_t offset);
|
||||
void eraseAuto(bool enable);
|
||||
|
||||
std::vector<bool> getLockRegions();
|
||||
|
||||
bool getSecurity();
|
||||
|
||||
bool getBod();
|
||||
bool canBod() { return true; }
|
||||
|
||||
bool getBor();
|
||||
bool canBor() { return true; }
|
||||
|
||||
bool getBootFlash();
|
||||
bool canBootFlash() { return _canBootFlash; }
|
||||
|
||||
void writeOptions();
|
||||
|
||||
void writePage(uint32_t page);
|
||||
void readPage(uint32_t page, uint8_t* data);
|
||||
|
||||
private:
|
||||
bool _canBootFlash;
|
||||
|
||||
void waitFSR(int seconds = 1);
|
||||
void writeFCR0(uint8_t cmd, uint32_t arg);
|
||||
void writeFCR1(uint8_t cmd, uint32_t arg);
|
||||
uint32_t readFSR0();
|
||||
uint32_t readFSR1();
|
||||
};
|
||||
|
||||
#endif // _EFCFLASH_H
|
|
@ -0,0 +1,94 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _FILEERROR_H
|
||||
#define _FILEERROR_H
|
||||
|
||||
#include <exception>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Flash.h"
|
||||
#include "Samba.h"
|
||||
|
||||
class FileError : public std::exception
|
||||
{
|
||||
public:
|
||||
FileError() : std::exception() {}
|
||||
};
|
||||
|
||||
class FileOpenError : public FileError
|
||||
{
|
||||
public:
|
||||
FileOpenError() : FileError(), _errnum(0) {};
|
||||
FileOpenError(int errnum) : FileError(), _errnum(errnum) {};
|
||||
const char* what() const throw()
|
||||
{
|
||||
if (_errnum == 0)
|
||||
return "Unable to open file";
|
||||
else
|
||||
return strerror(_errnum);
|
||||
}
|
||||
private:
|
||||
int _errnum;
|
||||
};
|
||||
|
||||
class FileIoError : public FileError
|
||||
{
|
||||
public:
|
||||
FileIoError() : FileError(), _errnum(0) {};
|
||||
FileIoError(int errnum) : FileError(), _errnum(errnum) {};
|
||||
const char* what() const throw()
|
||||
{
|
||||
if (_errnum == 0)
|
||||
return "File I/O operation failed";
|
||||
else
|
||||
return strerror(_errnum);
|
||||
}
|
||||
private:
|
||||
int _errnum;
|
||||
};
|
||||
|
||||
class FileShortError : public FileError
|
||||
{
|
||||
public:
|
||||
FileShortError() : FileError() {};
|
||||
const char* what() const throw()
|
||||
{
|
||||
return "Operation ended with a short write";
|
||||
}
|
||||
};
|
||||
|
||||
class FileSizeError : public FileError
|
||||
{
|
||||
public:
|
||||
FileSizeError() {};
|
||||
const char* what() const throw() { return "File operation exceeds flash size"; }
|
||||
};
|
||||
|
||||
#endif // _FILEERROR_H
|
|
@ -0,0 +1,106 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "Flash.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
Flash::Flash(Samba& samba,
|
||||
const std::string& name,
|
||||
uint32_t addr,
|
||||
uint32_t pages,
|
||||
uint32_t size,
|
||||
uint32_t planes,
|
||||
uint32_t lockRegions,
|
||||
uint32_t user,
|
||||
uint32_t stack)
|
||||
: _samba(samba), _name(name), _addr(addr), _pages(pages), _size(size),
|
||||
_planes(planes), _lockRegions(lockRegions), _user(user), _wordCopy(samba, user)
|
||||
{
|
||||
assert((size & (size - 1)) == 0);
|
||||
assert((pages & (pages - 1)) == 0);
|
||||
assert((lockRegions & (lockRegions - 1)) == 0);
|
||||
|
||||
_wordCopy.setWords(size / sizeof(uint32_t));
|
||||
_wordCopy.setStack(stack);
|
||||
|
||||
_onBufferA = true;
|
||||
|
||||
// page buffers will have the size of a physical page and will be situated right after the applet
|
||||
_pageBufferA = ((_user + _wordCopy.size() + 3) / 4) * 4; // we need to avoid non 32bits aligned access on Cortex-M0+
|
||||
_pageBufferB = _pageBufferA + size;
|
||||
}
|
||||
|
||||
void
|
||||
Flash::setLockRegions(const std::vector<bool>& regions)
|
||||
{
|
||||
if (regions.size() > _lockRegions)
|
||||
throw FlashRegionError();
|
||||
|
||||
_regions.set(regions);
|
||||
}
|
||||
|
||||
void
|
||||
Flash::setSecurity()
|
||||
{
|
||||
_security.set(true);
|
||||
}
|
||||
|
||||
void
|
||||
Flash::setBor(bool enable)
|
||||
{
|
||||
if (canBor())
|
||||
_bor.set(enable);
|
||||
}
|
||||
|
||||
void
|
||||
Flash::setBod(bool enable)
|
||||
{
|
||||
if (canBod())
|
||||
_bod.set(enable);
|
||||
}
|
||||
|
||||
void
|
||||
Flash::setBootFlash(bool enable)
|
||||
{
|
||||
if (canBootFlash())
|
||||
_bootFlash.set(enable);
|
||||
}
|
||||
|
||||
void
|
||||
Flash::loadBuffer(const uint8_t* data, uint16_t bufferSize)
|
||||
{
|
||||
_samba.write(_onBufferA ? _pageBufferA : _pageBufferB, data, bufferSize);
|
||||
}
|
||||
|
||||
void
|
||||
Flash::writeBuffer(uint32_t dst_addr, uint32_t size)
|
||||
{
|
||||
_samba.writeBuffer(_onBufferA ? _pageBufferA : _pageBufferB, dst_addr + _addr, size);
|
||||
}
|
||||
|
|
@ -0,0 +1,180 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _FLASH_H
|
||||
#define _FLASH_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <exception>
|
||||
|
||||
#include "Samba.h"
|
||||
#include "WordCopyApplet.h"
|
||||
|
||||
class FlashPageError : public std::exception
|
||||
{
|
||||
public:
|
||||
FlashPageError() : exception() {};
|
||||
const char* what() const throw() { return "Invalid flash page"; }
|
||||
};
|
||||
|
||||
class FlashRegionError : public std::exception
|
||||
{
|
||||
public:
|
||||
FlashRegionError() : exception() {};
|
||||
const char* what() const throw() { return "Invalid lock region"; }
|
||||
};
|
||||
|
||||
class FlashLockError : public std::exception
|
||||
{
|
||||
public:
|
||||
FlashLockError() : exception() {};
|
||||
const char* what() const throw() { return "Flash page is locked"; }
|
||||
};
|
||||
|
||||
class FlashCmdError : public std::exception
|
||||
{
|
||||
public:
|
||||
FlashCmdError() : exception() {};
|
||||
const char* what() const throw() { return "Flash command failed"; }
|
||||
};
|
||||
|
||||
class FlashTimeoutError : public std::exception
|
||||
{
|
||||
public:
|
||||
FlashTimeoutError() : exception() {};
|
||||
const char* what() const throw() { return "Flash command timeout"; }
|
||||
};
|
||||
|
||||
class BootFlashError : public std::exception
|
||||
{
|
||||
public:
|
||||
BootFlashError() : exception() {};
|
||||
const char* what() const throw() { return "Unable to clear boot flash for this device"; }
|
||||
|
||||
};
|
||||
|
||||
class FlashEraseError : public std::exception
|
||||
{
|
||||
public:
|
||||
FlashEraseError() : exception() {};
|
||||
const char* what() const throw() { return "Flash erase failed"; }
|
||||
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class FlashOption
|
||||
{
|
||||
public:
|
||||
FlashOption() : _dirty(false) {}
|
||||
virtual ~FlashOption() {}
|
||||
void set(const T& value) { _value = value; _dirty = true; }
|
||||
const T& get() { return _value; }
|
||||
bool isDirty() { return _dirty; }
|
||||
|
||||
private:
|
||||
T _value;
|
||||
bool _dirty;
|
||||
};
|
||||
|
||||
class Flash
|
||||
{
|
||||
public:
|
||||
Flash(Samba& samba,
|
||||
const std::string& name,
|
||||
uint32_t addr, // Flash base address
|
||||
uint32_t pages, // Number of pages
|
||||
uint32_t size, // Page size in bytes
|
||||
uint32_t planes, // Number of flash planes
|
||||
uint32_t lockRegions, // Number of flash lock regions
|
||||
uint32_t user, // Address in SRAM where the applet and buffers will be placed
|
||||
uint32_t stack); // Address in SRAM where the applet stack will be placed
|
||||
virtual ~Flash() {}
|
||||
|
||||
const std::string& name() { return _name; }
|
||||
|
||||
virtual uint32_t address() { return _addr; }
|
||||
virtual uint32_t pageSize() { return _size; }
|
||||
virtual uint32_t numPages() { return _pages; }
|
||||
virtual uint32_t numPlanes() { return _planes; }
|
||||
virtual uint32_t totalSize() { return _size * _pages; }
|
||||
virtual uint32_t lockRegions() { return _lockRegions; }
|
||||
|
||||
virtual void eraseAll(uint32_t offset) = 0;
|
||||
virtual void eraseAuto(bool enable) = 0;
|
||||
|
||||
virtual std::vector<bool> getLockRegions() = 0;
|
||||
virtual void setLockRegions(const std::vector<bool>& regions);
|
||||
|
||||
virtual bool getSecurity() = 0;
|
||||
virtual void setSecurity();
|
||||
|
||||
virtual bool getBod() = 0;
|
||||
virtual void setBod(bool enable);
|
||||
virtual bool canBod() = 0;
|
||||
|
||||
virtual bool getBor() = 0;
|
||||
virtual void setBor(bool enable);
|
||||
virtual bool canBor() = 0;
|
||||
|
||||
virtual bool getBootFlash() = 0;
|
||||
virtual void setBootFlash(bool enable);
|
||||
virtual bool canBootFlash() = 0;
|
||||
|
||||
virtual void writeOptions() = 0;
|
||||
|
||||
virtual void writePage(uint32_t page) = 0;
|
||||
virtual void readPage(uint32_t page, uint8_t* data) = 0;
|
||||
|
||||
virtual void writeBuffer(uint32_t dst_addr, uint32_t size);
|
||||
virtual void loadBuffer(const uint8_t* data, uint16_t size);
|
||||
|
||||
protected:
|
||||
Samba& _samba;
|
||||
std::string _name;
|
||||
uint32_t _addr;
|
||||
uint32_t _pages;
|
||||
uint32_t _size;
|
||||
uint32_t _planes;
|
||||
uint32_t _lockRegions;
|
||||
uint32_t _user;
|
||||
WordCopyApplet _wordCopy;
|
||||
|
||||
FlashOption<bool> _bootFlash;
|
||||
FlashOption< std::vector<bool> > _regions;
|
||||
FlashOption<bool> _bod;
|
||||
FlashOption<bool> _bor;
|
||||
FlashOption<bool> _security;
|
||||
|
||||
bool _onBufferA;
|
||||
uint32_t _pageBufferA;
|
||||
uint32_t _pageBufferB;
|
||||
};
|
||||
|
||||
#endif // _FLASH_H
|
|
@ -0,0 +1,373 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "Flasher.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
void
|
||||
FlasherInfo::print()
|
||||
{
|
||||
bool first;
|
||||
|
||||
printf("Device : %s\n", name.c_str());
|
||||
printf("Version : %s\n", version.c_str());
|
||||
printf("Address : 0x%x\n", address);
|
||||
printf("Pages : %d\n", numPages);
|
||||
printf("Page Size : %d bytes\n", pageSize);
|
||||
printf("Total Size : %dKB\n", totalSize / 1024);
|
||||
printf("Planes : %d\n", numPlanes);
|
||||
printf("Lock Regions : %zd\n", lockRegions.size());
|
||||
printf("Locked : ");
|
||||
first = true;
|
||||
for (uint32_t region = 0; region < lockRegions.size(); region++)
|
||||
{
|
||||
if (lockRegions[region])
|
||||
{
|
||||
printf("%s%d", first ? "" : ",", region);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
printf("%s\n", first ? "none" : "");
|
||||
printf("Security : %s\n", security ? "true" : "false");
|
||||
if (canBootFlash)
|
||||
printf("Boot Flash : %s\n", bootFlash ? "true" : "false");
|
||||
if (canBod)
|
||||
printf("BOD : %s\n", bod ? "true" : "false");
|
||||
if (canBor)
|
||||
printf("BOR : %s\n", bor ? "true" : "false");
|
||||
}
|
||||
|
||||
void
|
||||
Flasher::erase(uint32_t foffset)
|
||||
{
|
||||
_observer.onStatus("Erase flash\n");
|
||||
_flash->eraseAll(foffset);
|
||||
_flash->eraseAuto(false);
|
||||
}
|
||||
|
||||
void
|
||||
Flasher::write(const char* filename, uint32_t foffset)
|
||||
{
|
||||
FILE* infile;
|
||||
uint32_t pageSize = _flash->pageSize();
|
||||
uint32_t pageNum = 0;
|
||||
uint32_t numPages;
|
||||
long fsize;
|
||||
size_t fbytes;
|
||||
|
||||
if (foffset % pageSize != 0 || foffset >= _flash->totalSize())
|
||||
throw FlashOffsetError();
|
||||
|
||||
infile = fopen(filename, "rb");
|
||||
if (!infile)
|
||||
throw FileOpenError(errno);
|
||||
|
||||
try
|
||||
{
|
||||
if (fseek(infile, 0, SEEK_END) != 0 || (fsize = ftell(infile)) < 0)
|
||||
throw FileIoError(errno);
|
||||
|
||||
rewind(infile);
|
||||
|
||||
numPages = (fsize + pageSize - 1) / pageSize;
|
||||
if (numPages > _flash->numPages())
|
||||
throw FileSizeError();
|
||||
|
||||
_observer.onStatus("Write %ld bytes to flash (%u pages)\n", fsize, numPages);
|
||||
|
||||
if (_samba.canWriteBuffer())
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
uint32_t bufferSize = _samba.writeBufferSize();
|
||||
uint8_t buffer[bufferSize];
|
||||
|
||||
while ((fbytes = fread(buffer, 1, bufferSize, infile)) > 0)
|
||||
{
|
||||
_observer.onProgress(offset / pageSize, numPages);
|
||||
|
||||
if (fbytes < bufferSize)
|
||||
{
|
||||
memset(buffer + fbytes, 0, bufferSize - fbytes);
|
||||
fbytes = (fbytes + pageSize - 1) / pageSize * pageSize;
|
||||
}
|
||||
|
||||
_flash->loadBuffer(buffer, fbytes);
|
||||
_flash->writeBuffer(foffset + offset, fbytes);
|
||||
offset += fbytes;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t buffer[pageSize];
|
||||
uint32_t pageOffset = foffset / pageSize;
|
||||
|
||||
while ((fbytes = fread(buffer, 1, pageSize, infile)) > 0)
|
||||
{
|
||||
_observer.onProgress(pageNum, numPages);
|
||||
|
||||
_flash->loadBuffer(buffer, fbytes);
|
||||
_flash->writePage(pageOffset + pageNum);
|
||||
|
||||
pageNum++;
|
||||
if (pageNum == numPages || fbytes != pageSize)
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
fclose(infile);
|
||||
throw;
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
_observer.onProgress(numPages, numPages);
|
||||
}
|
||||
|
||||
bool
|
||||
Flasher::verify(const char* filename, uint32_t& pageErrors, uint32_t& totalErrors, uint32_t foffset)
|
||||
{
|
||||
FILE* infile;
|
||||
uint32_t pageSize = _flash->pageSize();
|
||||
uint8_t bufferA[pageSize];
|
||||
uint8_t bufferB[pageSize];
|
||||
uint32_t pageNum = 0;
|
||||
uint32_t numPages;
|
||||
uint32_t pageOffset;
|
||||
uint32_t byteErrors = 0;
|
||||
uint16_t calcCrc = 0;
|
||||
uint16_t flashCrc;
|
||||
long fsize;
|
||||
size_t fbytes;
|
||||
|
||||
pageErrors = 0;
|
||||
totalErrors = 0;
|
||||
|
||||
if (foffset % pageSize != 0 || foffset >= _flash->totalSize())
|
||||
throw FlashOffsetError();
|
||||
|
||||
pageOffset = foffset / pageSize;
|
||||
|
||||
infile = fopen(filename, "rb");
|
||||
if (!infile)
|
||||
throw FileOpenError(errno);
|
||||
|
||||
try
|
||||
{
|
||||
if (fseek(infile, 0, SEEK_END) != 0 || (fsize = ftell(infile)) < 0)
|
||||
throw FileIoError(errno);
|
||||
|
||||
rewind(infile);
|
||||
|
||||
numPages = (fsize + pageSize - 1) / pageSize;
|
||||
if (numPages > _flash->numPages())
|
||||
throw FileSizeError();
|
||||
|
||||
_observer.onStatus("Verify %ld bytes of flash\n", fsize);
|
||||
|
||||
while ((fbytes = fread(bufferA, 1, pageSize, infile)) > 0)
|
||||
{
|
||||
byteErrors = 0;
|
||||
|
||||
_observer.onProgress(pageNum, numPages);
|
||||
|
||||
if (_samba.canChecksumBuffer())
|
||||
{
|
||||
for (uint32_t i = 0; i < fbytes; i++)
|
||||
calcCrc = _samba.checksumCalc(bufferA[i], calcCrc);
|
||||
|
||||
flashCrc = _samba.checksumBuffer((pageOffset + pageNum) * pageSize, fbytes);
|
||||
|
||||
if (flashCrc != calcCrc)
|
||||
{
|
||||
_flash->readPage(pageOffset + pageNum, bufferB);
|
||||
|
||||
for (uint32_t i = 0; i < fbytes; i++)
|
||||
{
|
||||
if (bufferA[i] != bufferB[i])
|
||||
byteErrors++;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_flash->readPage(pageOffset + pageNum, bufferB);
|
||||
|
||||
for (uint32_t i = 0; i < fbytes; i++)
|
||||
{
|
||||
if (bufferA[i] != bufferB[i])
|
||||
byteErrors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (byteErrors != 0)
|
||||
{
|
||||
pageErrors++;
|
||||
totalErrors += byteErrors;
|
||||
}
|
||||
|
||||
pageNum++;
|
||||
if (pageNum == numPages || fbytes != pageSize)
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
fclose(infile);
|
||||
throw;
|
||||
}
|
||||
|
||||
fclose(infile);
|
||||
|
||||
_observer.onProgress(numPages, numPages);
|
||||
|
||||
if (pageErrors != 0)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
Flasher::read(const char* filename, uint32_t fsize, uint32_t foffset)
|
||||
{
|
||||
FILE* outfile;
|
||||
uint32_t pageSize = _flash->pageSize();
|
||||
uint8_t buffer[pageSize];
|
||||
uint32_t pageNum = 0;
|
||||
uint32_t pageOffset;
|
||||
uint32_t numPages;
|
||||
size_t fbytes;
|
||||
|
||||
if (foffset % pageSize != 0 || foffset >= _flash->totalSize())
|
||||
throw FlashOffsetError();
|
||||
|
||||
pageOffset = foffset / pageSize;
|
||||
|
||||
if (fsize == 0)
|
||||
fsize = pageSize * (_flash->numPages() - pageOffset);
|
||||
|
||||
numPages = (fsize + pageSize - 1) / pageSize;
|
||||
if (pageOffset + numPages > _flash->numPages())
|
||||
throw FileSizeError();
|
||||
|
||||
outfile = fopen(filename, "wb");
|
||||
if (!outfile)
|
||||
throw FileOpenError(errno);
|
||||
|
||||
_observer.onStatus("Read %d bytes from flash\n", fsize);
|
||||
|
||||
try
|
||||
{
|
||||
for (pageNum = 0; pageNum < numPages; pageNum++)
|
||||
{
|
||||
_observer.onProgress(pageNum, numPages);
|
||||
|
||||
_flash->readPage(pageOffset + pageNum, buffer);
|
||||
|
||||
if (pageNum == numPages - 1 && fsize % pageSize > 0)
|
||||
pageSize = fsize % pageSize;
|
||||
fbytes = fwrite(buffer, 1, pageSize, outfile);
|
||||
if (fbytes != pageSize)
|
||||
throw FileShortError();
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
fclose(outfile);
|
||||
throw;
|
||||
}
|
||||
|
||||
_observer.onProgress(numPages, numPages);
|
||||
|
||||
fclose(outfile);
|
||||
}
|
||||
|
||||
void
|
||||
Flasher::lock(string& regionArg, bool enable)
|
||||
{
|
||||
if (regionArg.empty())
|
||||
{
|
||||
_observer.onStatus("%s all regions\n", enable ? "Lock" : "Unlock");
|
||||
std::vector<bool> regions(_flash->lockRegions(), enable);
|
||||
_flash->setLockRegions(regions);
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t pos = 0;
|
||||
size_t delim;
|
||||
uint32_t region;
|
||||
string sub;
|
||||
std::vector<bool> regions = _flash->getLockRegions();
|
||||
|
||||
do
|
||||
{
|
||||
delim = regionArg.find(',', pos);
|
||||
sub = regionArg.substr(pos, delim - pos);
|
||||
region = strtol(sub.c_str(), NULL, 0);
|
||||
_observer.onStatus("%s region %d\n", enable ? "Lock" : "Unlock", region);
|
||||
regions[region] = enable;
|
||||
pos = delim + 1;
|
||||
} while (delim != string::npos);
|
||||
|
||||
_flash->setLockRegions(regions);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Flasher::info(FlasherInfo& info)
|
||||
{
|
||||
info.name = _flash->name();
|
||||
info.version = _samba.version();
|
||||
info.address = _flash->address();
|
||||
info.numPages = _flash->numPages();
|
||||
info.pageSize = _flash->pageSize();
|
||||
info.totalSize = _flash->numPages() * _flash->pageSize();
|
||||
info.numPlanes = _flash->numPlanes();
|
||||
info.security = _flash->getSecurity();
|
||||
info.bootFlash = _flash->getBootFlash();
|
||||
info.bod = _flash->getBod();
|
||||
info.bor = _flash->getBor();
|
||||
|
||||
info.canBootFlash = _flash->canBootFlash();
|
||||
info.canBod = _flash->canBod();
|
||||
info.canBor = _flash->canBor();
|
||||
info.canChipErase = _samba.canChipErase();
|
||||
info.canWriteBuffer = _samba.canWriteBuffer();
|
||||
info.canChecksumBuffer = _samba.canChecksumBuffer();
|
||||
info.lockRegions = _flash->getLockRegions();
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _FLASHER_H
|
||||
#define _FLASHER_H
|
||||
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <vector>
|
||||
|
||||
#include "Device.h"
|
||||
#include "Flash.h"
|
||||
#include "Samba.h"
|
||||
#include "FileError.h"
|
||||
|
||||
class FlashOffsetError : public std::exception
|
||||
{
|
||||
public:
|
||||
FlashOffsetError() : std::exception() {};
|
||||
virtual const char* what() const throw() { return "Flash offset is invalid"; }
|
||||
};
|
||||
|
||||
class FlasherObserver
|
||||
{
|
||||
public:
|
||||
FlasherObserver() {}
|
||||
virtual ~FlasherObserver() {}
|
||||
|
||||
virtual void onStatus(const char *message, ...) = 0;
|
||||
virtual void onProgress(int num, int div) = 0;
|
||||
};
|
||||
|
||||
class FlasherInfo
|
||||
{
|
||||
public:
|
||||
FlasherInfo() {}
|
||||
virtual ~FlasherInfo() {}
|
||||
|
||||
void print();
|
||||
|
||||
std::string name;
|
||||
uint32_t chipId;
|
||||
uint32_t extChipId;
|
||||
std::string version;
|
||||
uint32_t address;
|
||||
uint32_t numPages;
|
||||
uint32_t pageSize;
|
||||
uint32_t totalSize;
|
||||
uint32_t numPlanes;
|
||||
|
||||
bool security;
|
||||
bool bootFlash;
|
||||
bool bod;
|
||||
bool bor;
|
||||
|
||||
bool canBootFlash;
|
||||
bool canBod;
|
||||
bool canBor;
|
||||
bool canChipErase;
|
||||
bool canWriteBuffer;
|
||||
bool canChecksumBuffer;
|
||||
|
||||
std::vector<bool> lockRegions;
|
||||
};
|
||||
|
||||
class Flasher
|
||||
{
|
||||
public:
|
||||
Flasher(Samba& samba, Device& device, FlasherObserver& observer) : _samba(samba), _flash(device.getFlash()), _observer(observer) {}
|
||||
virtual ~Flasher() {}
|
||||
|
||||
void erase(uint32_t foffset);
|
||||
void write(const char* filename, uint32_t foffset = 0);
|
||||
bool verify(const char* filename, uint32_t& pageErrors, uint32_t& totalErrors, uint32_t foffset = 0);
|
||||
void read(const char* filename, uint32_t fsize, uint32_t foffset = 0);
|
||||
void lock(std::string& regionArg, bool enable);
|
||||
void info(FlasherInfo& info);
|
||||
|
||||
private:
|
||||
Samba& _samba;
|
||||
Device::FlashPtr& _flash;
|
||||
FlasherObserver& _observer;
|
||||
};
|
||||
|
||||
#endif // _FLASHER_H
|
|
@ -0,0 +1,109 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "LinuxPortFactory.h"
|
||||
#include "PosixSerialPort.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
LinuxPortFactory::LinuxPortFactory()
|
||||
{
|
||||
_dir = opendir("/dev");
|
||||
}
|
||||
|
||||
LinuxPortFactory::~LinuxPortFactory()
|
||||
{
|
||||
if (_dir)
|
||||
closedir(_dir);
|
||||
}
|
||||
|
||||
SerialPort::Ptr
|
||||
LinuxPortFactory::create(const std::string& name)
|
||||
{
|
||||
bool isUsb = false;
|
||||
|
||||
if (name.find("ttyUSB") != std::string::npos ||
|
||||
name.find("ttyACM") != std::string::npos)
|
||||
isUsb = true;
|
||||
|
||||
return create(name, isUsb);
|
||||
}
|
||||
|
||||
SerialPort::Ptr
|
||||
LinuxPortFactory::create(const std::string& name, bool isUsb)
|
||||
{
|
||||
return SerialPort::Ptr(new PosixSerialPort(name, isUsb));
|
||||
}
|
||||
|
||||
std::string
|
||||
LinuxPortFactory::begin()
|
||||
{
|
||||
if (!_dir)
|
||||
return end();
|
||||
|
||||
rewinddir(_dir);
|
||||
|
||||
return next();
|
||||
}
|
||||
|
||||
std::string
|
||||
LinuxPortFactory::next()
|
||||
{
|
||||
struct dirent* entry;
|
||||
|
||||
if (!_dir)
|
||||
return end();
|
||||
|
||||
while ((entry = readdir(_dir)))
|
||||
{
|
||||
if (strncmp("ttyUSB", entry->d_name, sizeof("ttyUSB") - 1) == 0)
|
||||
return std::string(entry->d_name);
|
||||
else if (strncmp("ttyACM", entry->d_name, sizeof("ttyACM") - 1) == 0)
|
||||
return std::string(entry->d_name);
|
||||
else if (strncmp("ttyS", entry->d_name, sizeof("ttyS") - 1) == 0)
|
||||
return std::string(entry->d_name);
|
||||
}
|
||||
|
||||
return end();
|
||||
}
|
||||
|
||||
std::string
|
||||
LinuxPortFactory::end()
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string
|
||||
LinuxPortFactory::def()
|
||||
{
|
||||
return std::string("/dev/ttyACM0");
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _LINUXPORTFACTORY_H
|
||||
#define _LINUXPORTFACTORY_H
|
||||
|
||||
class LinuxPortFactory;
|
||||
#include "PortFactory.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
class LinuxPortFactory : public PortFactoryBase
|
||||
{
|
||||
public:
|
||||
LinuxPortFactory();
|
||||
virtual ~LinuxPortFactory();
|
||||
|
||||
virtual std::string begin();
|
||||
virtual std::string end();
|
||||
virtual std::string next();
|
||||
virtual std::string def();
|
||||
|
||||
virtual SerialPort::Ptr create(const std::string& name);
|
||||
virtual SerialPort::Ptr create(const std::string& name, bool isUsb);
|
||||
|
||||
private:
|
||||
std::string _empty;
|
||||
DIR* _dir;
|
||||
};
|
||||
|
||||
#endif // _LINUXPORTFACTORY_H
|
|
@ -0,0 +1,68 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _PORTFACTORY_H
|
||||
#define _PORTFACTORY_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "SerialPort.h"
|
||||
|
||||
class PortFactoryBase
|
||||
{
|
||||
public:
|
||||
PortFactoryBase() {}
|
||||
virtual ~PortFactoryBase() {}
|
||||
|
||||
virtual std::string begin() = 0;
|
||||
virtual std::string end() = 0;
|
||||
virtual std::string next() = 0;
|
||||
virtual std::string def() = 0;
|
||||
|
||||
virtual SerialPort::Ptr create(const std::string& name) = 0;
|
||||
virtual SerialPort::Ptr create(const std::string& name, bool isUsb) = 0;
|
||||
};
|
||||
|
||||
#if defined(__WIN32__)
|
||||
#include "WinPortFactory.h"
|
||||
typedef WinPortFactory PortFactory;
|
||||
#elif defined(__linux__)
|
||||
#include "LinuxPortFactory.h"
|
||||
typedef LinuxPortFactory PortFactory;
|
||||
#elif defined(__APPLE__)
|
||||
#include "OSXPortFactory.h"
|
||||
typedef OSXPortFactory PortFactory;
|
||||
#elif defined(__OpenBSD__) || defined(__FreeBSD__)
|
||||
// This is likely to work (but not tested) for the other BSDs as well
|
||||
#include "BSDPortFactory.h"
|
||||
typedef BSDPortFactory PortFactory;
|
||||
#else
|
||||
#error "Platform is not supported"
|
||||
#endif
|
||||
|
||||
#endif // _PORTFACTORY_H
|
|
@ -0,0 +1,332 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "PosixSerialPort.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <termios.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifndef B460800
|
||||
#define B460800 460800
|
||||
#endif
|
||||
#ifndef B921600
|
||||
#define B921600 921600
|
||||
#endif
|
||||
|
||||
PosixSerialPort::PosixSerialPort(const std::string& name, bool isUsb) :
|
||||
SerialPort(name), _devfd(-1), _isUsb(isUsb), _timeout(0),
|
||||
_autoFlush(false)
|
||||
{
|
||||
}
|
||||
|
||||
PosixSerialPort::~PosixSerialPort()
|
||||
{
|
||||
if (_devfd >= 0)
|
||||
::close(_devfd);
|
||||
}
|
||||
|
||||
bool
|
||||
PosixSerialPort::open(int baud,
|
||||
int data,
|
||||
SerialPort::Parity parity,
|
||||
SerialPort::StopBit stop)
|
||||
{
|
||||
struct termios options;
|
||||
speed_t speed;
|
||||
// Try opening port assuming _name is full path. If it fails
|
||||
// try "/dev/" + _name
|
||||
_devfd = ::open(_name.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
if (_devfd == -1)
|
||||
{
|
||||
std::string dev("/dev/");
|
||||
dev += _name;
|
||||
_devfd = ::open(dev.c_str(), O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
if (_devfd == -1)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (tcgetattr(_devfd, &options) == -1)
|
||||
{
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (baud)
|
||||
{
|
||||
case 1200:
|
||||
speed = B1200;
|
||||
break;
|
||||
case 9600:
|
||||
speed = B9600;
|
||||
break;
|
||||
case 19200:
|
||||
speed = B19200;
|
||||
break;
|
||||
case 38400:
|
||||
speed = B38400;
|
||||
break;
|
||||
case 57600:
|
||||
speed = B57600;
|
||||
break;
|
||||
case 115200:
|
||||
speed = B115200;
|
||||
break;
|
||||
case 230400:
|
||||
speed = B230400;
|
||||
break;
|
||||
case 460800:
|
||||
speed = B460800;
|
||||
break;
|
||||
case 921600:
|
||||
speed = B921600;
|
||||
break;
|
||||
default:
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cfsetispeed(&options, speed) || cfsetospeed(&options, speed))
|
||||
{
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
options.c_cflag |= (CLOCAL | CREAD);
|
||||
|
||||
switch (data)
|
||||
{
|
||||
case 8:
|
||||
options.c_cflag &= ~CSIZE;
|
||||
options.c_cflag |= CS8;
|
||||
break;
|
||||
case 7:
|
||||
options.c_cflag &= ~CSIZE;
|
||||
options.c_cflag |= CS7;
|
||||
break;
|
||||
default:
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (parity)
|
||||
{
|
||||
case SerialPort::ParityNone:
|
||||
options.c_cflag &= ~PARENB;
|
||||
options.c_cflag &= ~PARODD;
|
||||
options.c_iflag &= ~(INPCK | ISTRIP);
|
||||
break;
|
||||
case SerialPort::ParityOdd:
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag |= PARODD;
|
||||
options.c_iflag |= (INPCK | ISTRIP);
|
||||
break;
|
||||
case SerialPort::ParityEven:
|
||||
options.c_cflag |= PARENB;
|
||||
options.c_cflag &= ~PARODD;
|
||||
options.c_iflag |= (INPCK | ISTRIP);
|
||||
break;
|
||||
default:
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (stop)
|
||||
{
|
||||
case StopBitOne:
|
||||
options.c_cflag &= ~CSTOPB;
|
||||
break;
|
||||
case StopBitTwo:
|
||||
options.c_cflag |= CSTOPB;
|
||||
break;
|
||||
default:
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
// No hardware flow control
|
||||
options.c_cflag &= ~CRTSCTS;
|
||||
|
||||
// No software flow control
|
||||
options.c_iflag &= ~(IXON | IXOFF | IXANY);
|
||||
|
||||
// Raw input
|
||||
options.c_iflag &= ~(BRKINT | ICRNL);
|
||||
options.c_lflag &= ~(ICANON | IEXTEN | ECHO | ECHOE | ISIG);
|
||||
|
||||
// Raw output
|
||||
options.c_oflag &= ~OPOST;
|
||||
|
||||
// No wait time
|
||||
options.c_cc[VMIN] = 0;
|
||||
options.c_cc[VTIME] = 0;
|
||||
|
||||
if (tcsetattr(_devfd, TCSANOW, &options))
|
||||
{
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PosixSerialPort::close()
|
||||
{
|
||||
if (_devfd >= 0)
|
||||
::close(_devfd);
|
||||
_devfd = -1;
|
||||
}
|
||||
|
||||
int
|
||||
PosixSerialPort::read(uint8_t* buffer, int len)
|
||||
{
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
int numread = 0;
|
||||
int retval;
|
||||
|
||||
if (_devfd == -1)
|
||||
return -1;
|
||||
|
||||
while (numread < len)
|
||||
{
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(_devfd, &fds);
|
||||
|
||||
tv.tv_sec = _timeout / 1000;
|
||||
tv.tv_usec = (_timeout % 1000) * 1000;
|
||||
|
||||
retval = select(_devfd + 1, &fds, NULL, NULL, &tv);
|
||||
|
||||
if (retval < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else if (retval == 0)
|
||||
{
|
||||
return numread;
|
||||
}
|
||||
else if (FD_ISSET(_devfd, &fds))
|
||||
{
|
||||
retval = ::read(_devfd, (uint8_t*) buffer + numread, len - numread);
|
||||
if (retval < 0)
|
||||
return -1;
|
||||
numread += retval;
|
||||
}
|
||||
}
|
||||
|
||||
return numread;
|
||||
}
|
||||
|
||||
int
|
||||
PosixSerialPort::write(const uint8_t* buffer, int len)
|
||||
{
|
||||
if (_devfd == -1)
|
||||
return -1;
|
||||
|
||||
int res = ::write(_devfd, buffer, len);
|
||||
// Used on macos to avoid upload errors
|
||||
if (_autoFlush)
|
||||
flush();
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
PosixSerialPort::get()
|
||||
{
|
||||
uint8_t byte;
|
||||
|
||||
if (_devfd == -1)
|
||||
return -1;
|
||||
|
||||
if (read(&byte, 1) != 1)
|
||||
return -1;
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
int
|
||||
PosixSerialPort::put(int c)
|
||||
{
|
||||
uint8_t byte;
|
||||
|
||||
byte = c;
|
||||
return write(&byte, 1);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
bool
|
||||
PosixSerialPort::timeout(int millisecs)
|
||||
{
|
||||
_timeout = millisecs;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
PosixSerialPort::setDTR(bool dtr)
|
||||
{
|
||||
if (_devfd == -1)
|
||||
return;
|
||||
|
||||
int iFlags = TIOCM_DTR;
|
||||
|
||||
ioctl(_devfd, (dtr ? TIOCMBIS : TIOCMBIC), &iFlags);
|
||||
}
|
||||
|
||||
void
|
||||
PosixSerialPort::setRTS(bool rts)
|
||||
{
|
||||
if (_devfd == -1)
|
||||
return;
|
||||
|
||||
int iFlags = TIOCM_RTS;
|
||||
|
||||
ioctl(_devfd, (rts ? TIOCMBIS : TIOCMBIC), &iFlags);
|
||||
}
|
||||
|
||||
void
|
||||
PosixSerialPort::setAutoFlush(bool autoflush)
|
||||
{
|
||||
_autoFlush = autoflush;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _POSIXSERIALPORT_H
|
||||
#define _POSIXSERIALPORT_H
|
||||
|
||||
#include "SerialPort.h"
|
||||
|
||||
class PosixSerialPort : public SerialPort
|
||||
{
|
||||
public:
|
||||
PosixSerialPort(const std::string& name, bool isUsb);
|
||||
virtual ~PosixSerialPort();
|
||||
|
||||
bool open(int baud = 115200,
|
||||
int data = 8,
|
||||
SerialPort::Parity parity = SerialPort::ParityNone,
|
||||
SerialPort::StopBit stop = SerialPort::StopBitOne);
|
||||
void close();
|
||||
|
||||
bool isUsb() { return _isUsb; };
|
||||
|
||||
int read(uint8_t* data, int size);
|
||||
int write(const uint8_t* data, int size);
|
||||
int get();
|
||||
int put(int c);
|
||||
|
||||
bool timeout(int millisecs);
|
||||
void flush();
|
||||
void setDTR(bool dtr);
|
||||
void setRTS(bool rts);
|
||||
void setAutoFlush(bool autoflush);
|
||||
|
||||
private:
|
||||
int _devfd;
|
||||
bool _isUsb;
|
||||
int _timeout;
|
||||
bool _autoFlush;
|
||||
};
|
||||
|
||||
#endif // _POSIXSERIALPORT_H
|
|
@ -0,0 +1,672 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "Samba.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// XMODEM definitions
|
||||
#define BLK_SIZE 128
|
||||
#define MAX_RETRIES 5
|
||||
#define SOH 0x01
|
||||
#define EOT 0x04
|
||||
#define ACK 0x06
|
||||
#define NAK 0x15
|
||||
#define CAN 0x18
|
||||
#define START 'C'
|
||||
|
||||
#define TIMEOUT_QUICK 100
|
||||
#define TIMEOUT_NORMAL 1000
|
||||
#define TIMEOUT_LONG 5000
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
Samba::Samba() :
|
||||
_canChipErase(false),
|
||||
_canWriteBuffer(false),
|
||||
_canChecksumBuffer(false),
|
||||
_readBufferSize(0),
|
||||
_debug(false),
|
||||
_isUsb(false)
|
||||
{
|
||||
}
|
||||
|
||||
Samba::~Samba()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Samba::init()
|
||||
{
|
||||
uint8_t cmd[3];
|
||||
|
||||
_port->timeout(TIMEOUT_QUICK);
|
||||
|
||||
// Flush garbage
|
||||
uint8_t dummy[1024];
|
||||
_port->read(dummy, sizeof(dummy));
|
||||
|
||||
if (!_isUsb)
|
||||
{
|
||||
if (_debug)
|
||||
printf("Send auto-baud\n");
|
||||
|
||||
// RS-232 auto-baud sequence
|
||||
_port->put(0x80);
|
||||
_port->get();
|
||||
_port->put(0x80);
|
||||
_port->get();
|
||||
_port->put('#');
|
||||
_port->read(cmd, 3);
|
||||
}
|
||||
|
||||
// Set binary mode
|
||||
if (_debug)
|
||||
printf("Set binary mode\n");
|
||||
cmd[0] = 'N';
|
||||
cmd[1] = '#';
|
||||
_port->write(cmd, 2);
|
||||
_port->read(cmd, 2);
|
||||
|
||||
std::string ver;
|
||||
try
|
||||
{
|
||||
ver = version();
|
||||
}
|
||||
catch(SambaError& err)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::size_t extIndex = ver.find("[Arduino:");
|
||||
if (extIndex != string::npos)
|
||||
{
|
||||
extIndex += 9;
|
||||
while (ver[extIndex] != ']')
|
||||
{
|
||||
switch (ver[extIndex])
|
||||
{
|
||||
case 'X': _canChipErase = true; break;
|
||||
case 'Y': _canWriteBuffer = true; break;
|
||||
case 'Z': _canChecksumBuffer = true; break;
|
||||
}
|
||||
extIndex++;
|
||||
}
|
||||
|
||||
// All SAMD-based Arduino/AdaFruit boards have a bug in their bootloader
|
||||
// that trying to read 64 bytes or more over USB corrupts the data.
|
||||
// We must limit these boards to read chunks of 63 bytes.
|
||||
if (_isUsb)
|
||||
_readBufferSize = 63;
|
||||
}
|
||||
|
||||
_port->timeout(TIMEOUT_NORMAL);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Samba::connect(SerialPort::Ptr port, int bps)
|
||||
{
|
||||
_port = move(port);
|
||||
|
||||
// Try to connect at a high speed if USB
|
||||
_isUsb = _port->isUsb();
|
||||
if (_isUsb)
|
||||
{
|
||||
if (_port->open(921600) && init())
|
||||
{
|
||||
if (_debug)
|
||||
printf("Connected at 921600 baud\n");
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_port->close();
|
||||
}
|
||||
}
|
||||
_isUsb = false;
|
||||
|
||||
// Try the serial port at slower speed
|
||||
if (_port->open(bps) && init())
|
||||
{
|
||||
if (_debug)
|
||||
printf("Connected at %d baud\n", bps);
|
||||
return true;
|
||||
}
|
||||
|
||||
disconnect();
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
Samba::disconnect()
|
||||
{
|
||||
_port->close();
|
||||
_port.release();
|
||||
}
|
||||
|
||||
void
|
||||
Samba::writeByte(uint32_t addr, uint8_t value)
|
||||
{
|
||||
uint8_t cmd[14];
|
||||
|
||||
if (_debug)
|
||||
printf("%s(addr=%#x,value=%#x)\n", __FUNCTION__, addr, value);
|
||||
|
||||
snprintf((char*) cmd, sizeof(cmd), "O%08X,%02X#", addr, value);
|
||||
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
|
||||
throw SambaError();
|
||||
|
||||
// The SAM firmware has a bug that if the command and binary data
|
||||
// are received in the same USB data packet, then the firmware
|
||||
// gets confused. Even though the writes are separated in the code,
|
||||
// USB drivers often do write combining which can put them together
|
||||
// in the same USB data packet. To avoid this, we call the serial
|
||||
// port object's flush method before writing the data.
|
||||
if (_isUsb)
|
||||
_port->flush();
|
||||
}
|
||||
|
||||
uint8_t
|
||||
Samba::readByte(uint32_t addr)
|
||||
{
|
||||
uint8_t cmd[13];
|
||||
uint8_t value;
|
||||
|
||||
snprintf((char*) cmd, sizeof(cmd), "o%08X,4#", addr);
|
||||
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
|
||||
throw SambaError();
|
||||
if (_port->read(cmd, sizeof(uint8_t)) != sizeof(uint8_t))
|
||||
throw SambaError();
|
||||
|
||||
value = cmd[0];
|
||||
|
||||
if (_debug)
|
||||
printf("%s(addr=%#x)=%#x\n", __FUNCTION__, addr, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
Samba::writeWord(uint32_t addr, uint32_t value)
|
||||
{
|
||||
uint8_t cmd[20];
|
||||
|
||||
if (_debug)
|
||||
printf("%s(addr=%#x,value=%#x)\n", __FUNCTION__, addr, value);
|
||||
|
||||
snprintf((char*) cmd, sizeof(cmd), "W%08X,%08X#", addr, value);
|
||||
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
|
||||
throw SambaError();
|
||||
|
||||
// The SAM firmware has a bug that if the command and binary data
|
||||
// are received in the same USB data packet, then the firmware
|
||||
// gets confused. Even though the writes are sperated in the code,
|
||||
// USB drivers often do write combining which can put them together
|
||||
// in the same USB data packet. To avoid this, we call the serial
|
||||
// port object's flush method before writing the data.
|
||||
if (_isUsb)
|
||||
_port->flush();
|
||||
}
|
||||
|
||||
|
||||
uint32_t
|
||||
Samba::readWord(uint32_t addr)
|
||||
{
|
||||
uint8_t cmd[13];
|
||||
uint32_t value;
|
||||
|
||||
snprintf((char*) cmd, sizeof(cmd), "w%08X,4#", addr);
|
||||
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
|
||||
throw SambaError();
|
||||
if (_port->read(cmd, sizeof(uint32_t)) != sizeof(uint32_t))
|
||||
throw SambaError();
|
||||
|
||||
value = (cmd[3] << 24 | cmd[2] << 16 | cmd[1] << 8 | cmd[0] << 0);
|
||||
|
||||
if (_debug)
|
||||
printf("%s(addr=%#x)=%#x\n", __FUNCTION__, addr, value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static const uint16_t crc16Table[256] = {
|
||||
0x0000,0x1021,0x2042,0x3063,0x4084,0x50a5,0x60c6,0x70e7,
|
||||
0x8108,0x9129,0xa14a,0xb16b,0xc18c,0xd1ad,0xe1ce,0xf1ef,
|
||||
0x1231,0x0210,0x3273,0x2252,0x52b5,0x4294,0x72f7,0x62d6,
|
||||
0x9339,0x8318,0xb37b,0xa35a,0xd3bd,0xc39c,0xf3ff,0xe3de,
|
||||
0x2462,0x3443,0x0420,0x1401,0x64e6,0x74c7,0x44a4,0x5485,
|
||||
0xa56a,0xb54b,0x8528,0x9509,0xe5ee,0xf5cf,0xc5ac,0xd58d,
|
||||
0x3653,0x2672,0x1611,0x0630,0x76d7,0x66f6,0x5695,0x46b4,
|
||||
0xb75b,0xa77a,0x9719,0x8738,0xf7df,0xe7fe,0xd79d,0xc7bc,
|
||||
0x48c4,0x58e5,0x6886,0x78a7,0x0840,0x1861,0x2802,0x3823,
|
||||
0xc9cc,0xd9ed,0xe98e,0xf9af,0x8948,0x9969,0xa90a,0xb92b,
|
||||
0x5af5,0x4ad4,0x7ab7,0x6a96,0x1a71,0x0a50,0x3a33,0x2a12,
|
||||
0xdbfd,0xcbdc,0xfbbf,0xeb9e,0x9b79,0x8b58,0xbb3b,0xab1a,
|
||||
0x6ca6,0x7c87,0x4ce4,0x5cc5,0x2c22,0x3c03,0x0c60,0x1c41,
|
||||
0xedae,0xfd8f,0xcdec,0xddcd,0xad2a,0xbd0b,0x8d68,0x9d49,
|
||||
0x7e97,0x6eb6,0x5ed5,0x4ef4,0x3e13,0x2e32,0x1e51,0x0e70,
|
||||
0xff9f,0xefbe,0xdfdd,0xcffc,0xbf1b,0xaf3a,0x9f59,0x8f78,
|
||||
0x9188,0x81a9,0xb1ca,0xa1eb,0xd10c,0xc12d,0xf14e,0xe16f,
|
||||
0x1080,0x00a1,0x30c2,0x20e3,0x5004,0x4025,0x7046,0x6067,
|
||||
0x83b9,0x9398,0xa3fb,0xb3da,0xc33d,0xd31c,0xe37f,0xf35e,
|
||||
0x02b1,0x1290,0x22f3,0x32d2,0x4235,0x5214,0x6277,0x7256,
|
||||
0xb5ea,0xa5cb,0x95a8,0x8589,0xf56e,0xe54f,0xd52c,0xc50d,
|
||||
0x34e2,0x24c3,0x14a0,0x0481,0x7466,0x6447,0x5424,0x4405,
|
||||
0xa7db,0xb7fa,0x8799,0x97b8,0xe75f,0xf77e,0xc71d,0xd73c,
|
||||
0x26d3,0x36f2,0x0691,0x16b0,0x6657,0x7676,0x4615,0x5634,
|
||||
0xd94c,0xc96d,0xf90e,0xe92f,0x99c8,0x89e9,0xb98a,0xa9ab,
|
||||
0x5844,0x4865,0x7806,0x6827,0x18c0,0x08e1,0x3882,0x28a3,
|
||||
0xcb7d,0xdb5c,0xeb3f,0xfb1e,0x8bf9,0x9bd8,0xabbb,0xbb9a,
|
||||
0x4a75,0x5a54,0x6a37,0x7a16,0x0af1,0x1ad0,0x2ab3,0x3a92,
|
||||
0xfd2e,0xed0f,0xdd6c,0xcd4d,0xbdaa,0xad8b,0x9de8,0x8dc9,
|
||||
0x7c26,0x6c07,0x5c64,0x4c45,0x3ca2,0x2c83,0x1ce0,0x0cc1,
|
||||
0xef1f,0xff3e,0xcf5d,0xdf7c,0xaf9b,0xbfba,0x8fd9,0x9ff8,
|
||||
0x6e17,0x7e36,0x4e55,0x5e74,0x2e93,0x3eb2,0x0ed1,0x1ef0
|
||||
};
|
||||
|
||||
uint16_t
|
||||
Samba::crc16Calc(const uint8_t *data, int len)
|
||||
{
|
||||
uint16_t crc16 = 0;
|
||||
|
||||
while (len-- > 0)
|
||||
crc16 = (crc16 << 8) ^ crc16Table[((crc16 >> 8) ^ *(uint8_t*) data++) & 0xff];
|
||||
return crc16;
|
||||
}
|
||||
|
||||
bool
|
||||
Samba::crc16Check(const uint8_t *blk)
|
||||
{
|
||||
uint16_t crc16;
|
||||
|
||||
crc16 = blk[BLK_SIZE + 3] << 8 | blk[BLK_SIZE + 4];
|
||||
return (crc16Calc(&blk[3], BLK_SIZE) == crc16);
|
||||
}
|
||||
|
||||
void
|
||||
Samba::crc16Add(uint8_t *blk)
|
||||
{
|
||||
uint16_t crc16;
|
||||
|
||||
crc16 = crc16Calc(&blk[3], BLK_SIZE);
|
||||
blk[BLK_SIZE + 3] = (crc16 >> 8) & 0xff;
|
||||
blk[BLK_SIZE + 4] = crc16 & 0xff;
|
||||
}
|
||||
|
||||
uint16_t
|
||||
Samba::checksumCalc(uint8_t data, uint16_t crc16) {
|
||||
return (crc16 << 8) ^ crc16Table[((crc16 >> 8) ^ data) & 0xff];
|
||||
}
|
||||
|
||||
void
|
||||
Samba::readXmodem(uint8_t* buffer, int size)
|
||||
{
|
||||
uint8_t blk[BLK_SIZE + 5];
|
||||
uint32_t blkNum = 1;
|
||||
int retries;
|
||||
int bytes;
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
for (retries = 0; retries < MAX_RETRIES; retries++)
|
||||
{
|
||||
if (blkNum == 1)
|
||||
_port->put(START);
|
||||
|
||||
bytes = _port->read(blk, sizeof(blk));
|
||||
if (bytes == sizeof(blk) &&
|
||||
blk[0] == SOH &&
|
||||
blk[1] == (blkNum & 0xff) &&
|
||||
crc16Check(blk))
|
||||
break;
|
||||
|
||||
if (blkNum != 1)
|
||||
_port->put(NAK);
|
||||
}
|
||||
if (retries == MAX_RETRIES)
|
||||
throw SambaError();
|
||||
|
||||
_port->put(ACK);
|
||||
|
||||
memmove(buffer, &blk[3], min(size, BLK_SIZE));
|
||||
buffer += BLK_SIZE;
|
||||
size -= BLK_SIZE;
|
||||
blkNum++;
|
||||
}
|
||||
|
||||
for (retries = 0; retries < MAX_RETRIES; retries++)
|
||||
{
|
||||
if (_port->get() == EOT)
|
||||
{
|
||||
_port->put(ACK);
|
||||
break;
|
||||
}
|
||||
_port->put(NAK);
|
||||
}
|
||||
if (retries == MAX_RETRIES)
|
||||
throw SambaError();
|
||||
}
|
||||
|
||||
void
|
||||
Samba::writeXmodem(const uint8_t* buffer, int size)
|
||||
{
|
||||
uint8_t blk[BLK_SIZE + 5];
|
||||
uint32_t blkNum = 1;
|
||||
int retries;
|
||||
int bytes;
|
||||
|
||||
for (retries = 0; retries < MAX_RETRIES; retries++)
|
||||
{
|
||||
if (_port->get() == START)
|
||||
break;
|
||||
}
|
||||
if (retries == MAX_RETRIES)
|
||||
throw SambaError();
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
blk[0] = SOH;
|
||||
blk[1] = (blkNum & 0xff);
|
||||
blk[2] = ~(blkNum & 0xff);
|
||||
memmove(&blk[3], buffer, min(size, BLK_SIZE));
|
||||
if (size < BLK_SIZE)
|
||||
memset(&blk[3] + size, 0, BLK_SIZE - size);
|
||||
crc16Add(blk);
|
||||
|
||||
for (retries = 0; retries < MAX_RETRIES; retries++)
|
||||
{
|
||||
bytes = _port->write(blk, sizeof(blk));
|
||||
if (bytes != sizeof(blk))
|
||||
throw SambaError();
|
||||
|
||||
if (_port->get() == ACK)
|
||||
break;
|
||||
}
|
||||
|
||||
if (retries == MAX_RETRIES)
|
||||
throw SambaError();
|
||||
|
||||
buffer += BLK_SIZE;
|
||||
size -= BLK_SIZE;
|
||||
blkNum++;
|
||||
}
|
||||
|
||||
for (retries = 0; retries < MAX_RETRIES; retries++)
|
||||
{
|
||||
_port->put(EOT);
|
||||
if (_port->get() == ACK)
|
||||
break;
|
||||
}
|
||||
if (retries == MAX_RETRIES)
|
||||
throw SambaError();
|
||||
}
|
||||
|
||||
void
|
||||
Samba::readBinary(uint8_t* buffer, int size)
|
||||
{
|
||||
if (_port->read(buffer, size) != size)
|
||||
throw SambaError();
|
||||
}
|
||||
|
||||
void
|
||||
Samba::writeBinary(const uint8_t* buffer, int size)
|
||||
{
|
||||
while (size)
|
||||
{
|
||||
int written = _port->write(buffer, size);
|
||||
if (written <= 0)
|
||||
throw SambaError();
|
||||
buffer += written;
|
||||
size -= written;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Samba::read(uint32_t addr, uint8_t* buffer, int size)
|
||||
{
|
||||
uint8_t cmd[20];
|
||||
int chunk;
|
||||
|
||||
if (_debug)
|
||||
printf("%s(addr=%#x,size=%#x)\n", __FUNCTION__, addr, size);
|
||||
|
||||
// The SAM firmware has a bug reading powers of 2 over 32 bytes
|
||||
// via USB. If that is the case here, then read the first byte
|
||||
// with a readByte and then read one less than the requested size.
|
||||
if (_isUsb && _readBufferSize == 0 && size > 32 && !(size & (size - 1)))
|
||||
{
|
||||
*buffer = readByte(addr);
|
||||
addr++;
|
||||
buffer++;
|
||||
size--;
|
||||
}
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
// Handle any limitations on the size of the read
|
||||
if (_readBufferSize > 0 && size > _readBufferSize)
|
||||
chunk = _readBufferSize;
|
||||
else
|
||||
chunk = size;
|
||||
|
||||
snprintf((char*) cmd, sizeof(cmd), "R%08X,%08X#", addr, chunk);
|
||||
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
|
||||
throw SambaError();
|
||||
|
||||
if (_isUsb)
|
||||
readBinary(buffer, chunk);
|
||||
else
|
||||
readXmodem(buffer, chunk);
|
||||
|
||||
size -= chunk;
|
||||
addr += chunk;
|
||||
buffer += chunk;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Samba::write(uint32_t addr, const uint8_t* buffer, int size)
|
||||
{
|
||||
uint8_t cmd[20];
|
||||
|
||||
if (_debug)
|
||||
printf("%s(addr=%#x,size=%#x)\n", __FUNCTION__, addr, size);
|
||||
|
||||
snprintf((char*) cmd, sizeof(cmd), "S%08X,%08X#", addr, size);
|
||||
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
|
||||
throw SambaError();
|
||||
|
||||
// The SAM firmware has a bug that if the command and binary data
|
||||
// are received in the same USB data packet, then the firmware
|
||||
// gets confused. Even though the writes are separated in the code,
|
||||
// USB drivers often do write combining which can put them together
|
||||
// in the same USB data packet. To avoid this, we call the serial
|
||||
// port object's flush method before writing the data.
|
||||
if (_isUsb)
|
||||
{
|
||||
_port->flush();
|
||||
writeBinary(buffer, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
writeXmodem(buffer, size);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Samba::go(uint32_t addr)
|
||||
{
|
||||
uint8_t cmd[11];
|
||||
|
||||
if (_debug)
|
||||
printf("%s(addr=%#x)\n", __FUNCTION__, addr);
|
||||
|
||||
snprintf((char*) cmd, sizeof(cmd), "G%08X#", addr);
|
||||
if (_port->write(cmd, sizeof(cmd) - 1) != sizeof(cmd) - 1)
|
||||
throw SambaError();
|
||||
|
||||
// The SAM firmware can get confused if another command is
|
||||
// received in the same USB data packet as the go command
|
||||
// so we flush after writing the command over USB.
|
||||
if (_isUsb)
|
||||
_port->flush();
|
||||
}
|
||||
|
||||
std::string
|
||||
Samba::version()
|
||||
{
|
||||
uint8_t cmd[256];
|
||||
char* str;
|
||||
int size;
|
||||
int pos;
|
||||
|
||||
cmd[0] = 'V';
|
||||
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)
|
||||
{
|
||||
if (!_canChipErase)
|
||||
throw SambaError();
|
||||
|
||||
uint8_t cmd[64];
|
||||
|
||||
if (_debug)
|
||||
printf("%s(addr=%#x)\n", __FUNCTION__, start_addr);
|
||||
|
||||
int l = snprintf((char*) cmd, sizeof(cmd), "X%08X#", start_addr);
|
||||
if (_port->write(cmd, l) != l)
|
||||
throw SambaError();
|
||||
_port->timeout(TIMEOUT_LONG);
|
||||
_port->read(cmd, 3); // Expects "X\n\r"
|
||||
_port->timeout(TIMEOUT_NORMAL);
|
||||
if (cmd[0] != 'X')
|
||||
throw SambaError();
|
||||
}
|
||||
|
||||
void
|
||||
Samba::writeBuffer(uint32_t src_addr, uint32_t dst_addr, uint32_t size)
|
||||
{
|
||||
if (!_canWriteBuffer)
|
||||
throw SambaError();
|
||||
|
||||
if (size > checksumBufferSize())
|
||||
throw SambaError();
|
||||
|
||||
if (_debug)
|
||||
printf("%s(scr_addr=%#x, dst_addr=%#x, size=%#x)\n", __FUNCTION__, src_addr, dst_addr, size);
|
||||
|
||||
uint8_t cmd[64];
|
||||
int l = snprintf((char*) cmd, sizeof(cmd), "Y%08X,0#", src_addr);
|
||||
if (_port->write(cmd, l) != l)
|
||||
throw SambaError();
|
||||
_port->timeout(TIMEOUT_QUICK);
|
||||
cmd[0] = 0;
|
||||
_port->read(cmd, 3); // Expects "Y\n\r"
|
||||
_port->timeout(TIMEOUT_NORMAL);
|
||||
if (cmd[0] != 'Y')
|
||||
throw SambaError();
|
||||
|
||||
l = snprintf((char*) cmd, sizeof(cmd), "Y%08X,%08X#", dst_addr, size);
|
||||
if (_port->write(cmd, l) != l)
|
||||
throw SambaError();
|
||||
_port->timeout(TIMEOUT_LONG);
|
||||
cmd[0] = 0;
|
||||
_port->read(cmd, 3); // Expects "Y\n\r"
|
||||
_port->timeout(TIMEOUT_NORMAL);
|
||||
if (cmd[0] != 'Y')
|
||||
throw SambaError();
|
||||
}
|
||||
|
||||
uint16_t
|
||||
Samba::checksumBuffer(uint32_t start_addr, uint32_t size)
|
||||
{
|
||||
if (!_canChecksumBuffer)
|
||||
throw SambaError();
|
||||
|
||||
if (size > checksumBufferSize())
|
||||
throw SambaError();
|
||||
|
||||
if (_debug)
|
||||
printf("%s(start_addr=%#x, size=%#x) = ", __FUNCTION__, start_addr, size);
|
||||
|
||||
uint8_t cmd[64];
|
||||
int l = snprintf((char*) cmd, sizeof(cmd), "Z%08X,%08X#", start_addr, size);
|
||||
if (_port->write(cmd, l) != l)
|
||||
throw SambaError();
|
||||
_port->timeout(TIMEOUT_LONG);
|
||||
cmd[0] = 0;
|
||||
_port->read(cmd, 12); // Expects "Z00000000#\n\r"
|
||||
_port->timeout(TIMEOUT_NORMAL);
|
||||
if (cmd[0] != 'Z')
|
||||
throw SambaError();
|
||||
|
||||
cmd[9] = 0;
|
||||
errno = 0;
|
||||
uint32_t res = strtol((char*) &cmd[1], NULL, 16);
|
||||
if (errno != 0)
|
||||
throw SambaError();
|
||||
if (_debug)
|
||||
printf("%x\n", res);
|
||||
return res;
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _SAMBA_H
|
||||
#define _SAMBA_H
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
|
||||
#include "SerialPort.h"
|
||||
|
||||
class SambaError : public std::exception
|
||||
{
|
||||
public:
|
||||
SambaError() : exception() {};
|
||||
const char* what() const throw() { return "SAM-BA operation failed"; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
class Samba
|
||||
{
|
||||
public:
|
||||
Samba();
|
||||
virtual ~Samba();
|
||||
|
||||
bool connect(SerialPort::Ptr port, int bps = 115200);
|
||||
void disconnect();
|
||||
|
||||
void writeByte(uint32_t addr, uint8_t value);
|
||||
uint8_t readByte(uint32_t addr);
|
||||
|
||||
void writeWord(uint32_t addr, uint32_t value);
|
||||
uint32_t readWord(uint32_t addr);
|
||||
|
||||
void write(uint32_t addr, const uint8_t* buffer, int size);
|
||||
void read(uint32_t addr, uint8_t* buffer, int size);
|
||||
|
||||
void go(uint32_t addr);
|
||||
|
||||
std::string version();
|
||||
|
||||
void chipId(uint32_t& chipId, uint32_t& extChipId);
|
||||
|
||||
void setDebug(bool debug) { _debug = debug; }
|
||||
|
||||
const SerialPort& getSerialPort() { return *_port; }
|
||||
|
||||
void reset();
|
||||
|
||||
// Extended SAM-BA functions
|
||||
bool canChipErase() { return _canChipErase; }
|
||||
void chipErase(uint32_t start_addr);
|
||||
|
||||
bool canWriteBuffer() { return _canWriteBuffer; }
|
||||
void writeBuffer(uint32_t src_addr, uint32_t dst_addr, uint32_t size);
|
||||
uint32_t writeBufferSize() { return 4096; }
|
||||
|
||||
bool canChecksumBuffer() { return _canChecksumBuffer; }
|
||||
uint16_t checksumBuffer(uint32_t start_addr, uint32_t size);
|
||||
uint32_t checksumBufferSize() { return 4096; }
|
||||
uint16_t checksumCalc(uint8_t c, uint16_t crc);
|
||||
|
||||
private:
|
||||
bool _canChipErase;
|
||||
bool _canWriteBuffer;
|
||||
bool _canChecksumBuffer;
|
||||
int _readBufferSize;
|
||||
bool _debug;
|
||||
bool _isUsb;
|
||||
SerialPort::Ptr _port;
|
||||
|
||||
bool init();
|
||||
|
||||
uint16_t crc16Calc(const uint8_t *data, int len);
|
||||
bool crc16Check(const uint8_t *blk);
|
||||
void crc16Add(uint8_t *blk);
|
||||
void writeXmodem(const uint8_t* buffer, int size);
|
||||
void readXmodem(uint8_t* buffer, int size);
|
||||
|
||||
void writeBinary(const uint8_t* buffer, int size);
|
||||
void readBinary(uint8_t* buffer, int size);
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif // _SAMBA_H
|
|
@ -0,0 +1,82 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _SERIALPORT_H
|
||||
#define _SERIALPORT_H
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <stdint.h>
|
||||
|
||||
class SerialPort
|
||||
{
|
||||
public:
|
||||
SerialPort(const std::string& name) : _name(name) {}
|
||||
virtual ~SerialPort() {}
|
||||
|
||||
enum Parity
|
||||
{
|
||||
ParityNone,
|
||||
ParityOdd,
|
||||
ParityEven,
|
||||
};
|
||||
|
||||
enum StopBit
|
||||
{
|
||||
StopBitOne,
|
||||
StopBitOneFive,
|
||||
StopBitTwo,
|
||||
};
|
||||
|
||||
virtual bool open(int baud = 115200,
|
||||
int data = 8,
|
||||
Parity parity = ParityNone,
|
||||
StopBit stop = StopBitOne) = 0;
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual bool isUsb() = 0;
|
||||
|
||||
virtual int read(uint8_t* data, int size) = 0;
|
||||
virtual int write(const uint8_t* data, int size) = 0;
|
||||
virtual int get() = 0;
|
||||
virtual int put(int c) = 0;
|
||||
|
||||
virtual bool timeout(int millisecs) = 0;
|
||||
virtual void flush() = 0;
|
||||
virtual void setDTR(bool dtr) = 0;
|
||||
virtual void setRTS(bool rts) = 0;
|
||||
|
||||
virtual std::string name() const { return _name; }
|
||||
|
||||
typedef std::unique_ptr<SerialPort> Ptr;
|
||||
|
||||
protected:
|
||||
std::string _name;
|
||||
};
|
||||
|
||||
#endif // _SERIALPORT_H
|
|
@ -0,0 +1,62 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include "WordCopyApplet.h"
|
||||
|
||||
WordCopyApplet::WordCopyApplet(Samba& samba, uint32_t addr)
|
||||
: Applet(samba,
|
||||
addr,
|
||||
applet.code,
|
||||
sizeof(applet.code),
|
||||
addr + applet.start,
|
||||
addr + applet.stack,
|
||||
addr + applet.reset)
|
||||
{
|
||||
}
|
||||
|
||||
WordCopyApplet::~WordCopyApplet()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
WordCopyApplet::setDstAddr(uint32_t dstAddr)
|
||||
{
|
||||
_samba.writeWord(_addr + applet.dst_addr, dstAddr);
|
||||
}
|
||||
|
||||
void
|
||||
WordCopyApplet::setSrcAddr(uint32_t srcAddr)
|
||||
{
|
||||
_samba.writeWord(_addr + applet.src_addr, srcAddr);
|
||||
}
|
||||
|
||||
void
|
||||
WordCopyApplet::setWords(uint32_t words)
|
||||
{
|
||||
_samba.writeWord(_addr + applet.words, words);
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef _WORDCOPYAPPLET_H
|
||||
#define _WORDCOPYAPPLET_H
|
||||
|
||||
#include "Applet.h"
|
||||
#include "WordCopyArm.h"
|
||||
|
||||
class WordCopyApplet : public Applet
|
||||
{
|
||||
public:
|
||||
WordCopyApplet(Samba& samba, uint32_t addr);
|
||||
virtual ~WordCopyApplet();
|
||||
|
||||
void setDstAddr(uint32_t dstAddr);
|
||||
void setSrcAddr(uint32_t srcAddr);
|
||||
void setWords(uint32_t words);
|
||||
|
||||
private:
|
||||
static WordCopyArm applet;
|
||||
};
|
||||
|
||||
#endif // _WORDCOPYAPPLET_H
|
|
@ -0,0 +1,47 @@
|
|||
.global start
|
||||
.global stack
|
||||
.global reset
|
||||
.global dst_addr
|
||||
.global src_addr
|
||||
.global words
|
||||
|
||||
.text
|
||||
.thumb
|
||||
.align 0
|
||||
|
||||
start:
|
||||
ldr r0, dst_addr
|
||||
ldr r1, src_addr
|
||||
ldr r2, words
|
||||
b check
|
||||
|
||||
copy:
|
||||
ldmia r1!, {r3}
|
||||
stmia r0!, {r3}
|
||||
sub r2, #1
|
||||
|
||||
check:
|
||||
cmp r2, #0
|
||||
bne copy
|
||||
|
||||
@ Fix for SAM-BA stack bug
|
||||
ldr r0, reset
|
||||
cmp r0, #0
|
||||
bne return
|
||||
ldr r0, stack
|
||||
mov sp, r0
|
||||
|
||||
return:
|
||||
bx lr
|
||||
|
||||
.align 0
|
||||
stack:
|
||||
.word 0
|
||||
reset:
|
||||
.word 0
|
||||
dst_addr:
|
||||
.word 0
|
||||
src_addr:
|
||||
.word 0
|
||||
words:
|
||||
.word 0
|
|
@ -0,0 +1,25 @@
|
|||
// WARNING!!! DO NOT EDIT - FILE GENERATED BY APPLETGEN
|
||||
#include "WordCopyArm.h"
|
||||
#include "WordCopyApplet.h"
|
||||
|
||||
WordCopyArm WordCopyApplet::applet = {
|
||||
// dst_addr
|
||||
0x00000028,
|
||||
// reset
|
||||
0x00000024,
|
||||
// src_addr
|
||||
0x0000002c,
|
||||
// stack
|
||||
0x00000020,
|
||||
// start
|
||||
0x00000000,
|
||||
// words
|
||||
0x00000030,
|
||||
// code
|
||||
{
|
||||
0x09, 0x48, 0x0a, 0x49, 0x0a, 0x4a, 0x02, 0xe0, 0x08, 0xc9, 0x08, 0xc0, 0x01, 0x3a, 0x00, 0x2a,
|
||||
0xfa, 0xd1, 0x04, 0x48, 0x00, 0x28, 0x01, 0xd1, 0x01, 0x48, 0x85, 0x46, 0x70, 0x47, 0xc0, 0x46,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00,
|
||||
}
|
||||
};
|
|
@ -0,0 +1,18 @@
|
|||
// WARNING!!! DO NOT EDIT - FILE GENERATED BY APPLETGEN
|
||||
#ifndef _WORDCOPYARM_H
|
||||
#define _WORDCOPYARM_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t dst_addr;
|
||||
uint32_t reset;
|
||||
uint32_t src_addr;
|
||||
uint32_t stack;
|
||||
uint32_t start;
|
||||
uint32_t words;
|
||||
uint8_t code[52];
|
||||
} WordCopyArm;
|
||||
|
||||
#endif // _WORDCOPYARM_H
|
|
@ -0,0 +1,489 @@
|
|||
///////////////////////////////////////////////////////////////////////////////
|
||||
// BOSSA
|
||||
//
|
||||
// Copyright (c) 2011-2018, ShumaTech
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the <organization> nor the
|
||||
// names of its contributors may be used to endorse or promote products
|
||||
// derived from this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
// DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
||||
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
#include <string>
|
||||
#include <exception>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "CmdOpts.h"
|
||||
#include "Samba.h"
|
||||
#include "PortFactory.h"
|
||||
#include "Device.h"
|
||||
#include "Flasher.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
class BossaConfig
|
||||
{
|
||||
public:
|
||||
BossaConfig();
|
||||
virtual ~BossaConfig() {}
|
||||
|
||||
bool erase;
|
||||
bool write;
|
||||
bool read;
|
||||
bool verify;
|
||||
bool offset;
|
||||
bool reset;
|
||||
bool port;
|
||||
bool boot;
|
||||
bool bor;
|
||||
bool bod;
|
||||
bool lock;
|
||||
bool unlock;
|
||||
bool security;
|
||||
bool info;
|
||||
bool debug;
|
||||
bool help;
|
||||
bool usbPort;
|
||||
bool arduinoErase;
|
||||
|
||||
int readArg;
|
||||
int offsetArg;
|
||||
string portArg;
|
||||
int bootArg;
|
||||
int bodArg;
|
||||
int borArg;
|
||||
string lockArg;
|
||||
string unlockArg;
|
||||
bool usbPortArg;
|
||||
};
|
||||
|
||||
BossaConfig::BossaConfig()
|
||||
{
|
||||
erase = false;
|
||||
write = false;
|
||||
read = false;
|
||||
verify = false;
|
||||
port = false;
|
||||
boot = false;
|
||||
bod = false;
|
||||
bor = false;
|
||||
lock = false;
|
||||
security = false;
|
||||
info = false;
|
||||
help = false;
|
||||
usbPort = false;
|
||||
arduinoErase = false;
|
||||
|
||||
readArg = 0;
|
||||
offsetArg = 0;
|
||||
bootArg = 1;
|
||||
bodArg = 1;
|
||||
borArg = 1;
|
||||
usbPortArg=1;
|
||||
|
||||
reset = false;
|
||||
}
|
||||
|
||||
class BossaObserver : public FlasherObserver
|
||||
{
|
||||
public:
|
||||
BossaObserver() : _lastTicks(-1) {}
|
||||
virtual ~BossaObserver() {}
|
||||
|
||||
virtual void onStatus(const char *message, ...);
|
||||
virtual void onProgress(int num, int div);
|
||||
private:
|
||||
int _lastTicks;
|
||||
};
|
||||
|
||||
void
|
||||
BossaObserver::onStatus(const char *message, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, message);
|
||||
vprintf(message, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
BossaObserver::onProgress(int num, int div)
|
||||
{
|
||||
int ticks;
|
||||
int bars = 30;
|
||||
|
||||
ticks = num * bars / div;
|
||||
|
||||
if (ticks == _lastTicks)
|
||||
return;
|
||||
|
||||
printf("\r[");
|
||||
while (ticks-- > 0)
|
||||
{
|
||||
putchar('=');
|
||||
bars--;
|
||||
}
|
||||
while (bars-- > 0)
|
||||
{
|
||||
putchar(' ');
|
||||
}
|
||||
printf("] %d%% (%d/%d pages)", num * 100 / div, num, div);
|
||||
fflush(stdout);
|
||||
|
||||
_lastTicks = 0;
|
||||
}
|
||||
|
||||
static BossaConfig config;
|
||||
static Option opts[] =
|
||||
{
|
||||
{
|
||||
'e', "erase", &config.erase,
|
||||
{ ArgNone },
|
||||
"erase the entire flash starting at the offset"
|
||||
},
|
||||
{
|
||||
'w', "write", &config.write,
|
||||
{ ArgNone },
|
||||
"write FILE to the flash; accelerated when\n"
|
||||
"combined with erase option"
|
||||
},
|
||||
{
|
||||
'r', "read", &config.read,
|
||||
{ ArgOptional, ArgInt, "SIZE", { &config.readArg } },
|
||||
"read SIZE from flash and store in FILE;\n"
|
||||
"read entire flash if SIZE not specified"
|
||||
},
|
||||
{
|
||||
'v', "verify", &config.verify,
|
||||
{ ArgNone },
|
||||
"verify FILE matches flash contents"
|
||||
},
|
||||
{
|
||||
'o', "offset", &config.offset,
|
||||
{ ArgRequired, ArgInt, "OFFSET", { &config.offsetArg } },
|
||||
"start erase/write/read/verify operation at flash OFFSET;\n"
|
||||
"OFFSET must be aligned to a flash page boundary"
|
||||
},
|
||||
{
|
||||
'p', "port", &config.port,
|
||||
{ ArgRequired, ArgString, "PORT", { &config.portArg } },
|
||||
"use serial PORT to communicate to device;\n"
|
||||
"default behavior is to use first serial port"
|
||||
},
|
||||
{
|
||||
'b', "boot", &config.boot,
|
||||
{ ArgOptional, ArgInt, "BOOL", { &config.bootArg } },
|
||||
"boot from ROM if BOOL is 0;\n"
|
||||
"boot from FLASH if BOOL is 1 [default];\n"
|
||||
"option is ignored on unsupported devices"
|
||||
},
|
||||
{
|
||||
'c', "bod", &config.bod,
|
||||
{ ArgOptional, ArgInt, "BOOL", { &config.bodArg } },
|
||||
"no brownout detection if BOOL is 0;\n"
|
||||
"brownout detection is on if BOOL is 1 [default]"
|
||||
},
|
||||
{
|
||||
't', "bor", &config.bor,
|
||||
{ ArgOptional, ArgInt, "BOOL", { &config.borArg } },
|
||||
"no brownout reset if BOOL is 0;\n"
|
||||
"brownout reset is on if BOOL is 1 [default]"
|
||||
},
|
||||
{
|
||||
'l', "lock", &config.lock,
|
||||
{ ArgOptional, ArgString, "REGION", { &config.lockArg } },
|
||||
"lock the flash REGION as a comma-separated list;\n"
|
||||
"lock all if not given [default]"
|
||||
},
|
||||
{
|
||||
'u', "unlock", &config.unlock,
|
||||
{ ArgOptional, ArgString, "REGION", { &config.unlockArg } },
|
||||
"unlock the flash REGION as a comma-separated list;\n"
|
||||
"unlock all if not given [default]"
|
||||
},
|
||||
{
|
||||
's', "security", &config.security,
|
||||
{ ArgNone },
|
||||
"set the flash security flag"
|
||||
},
|
||||
{
|
||||
'i', "info", &config.info,
|
||||
{ ArgNone },
|
||||
"display device information"
|
||||
},
|
||||
{
|
||||
'd', "debug", &config.debug,
|
||||
{ ArgNone },
|
||||
"print debug messages"
|
||||
},
|
||||
{
|
||||
'h', "help", &config.help,
|
||||
{ ArgNone },
|
||||
"display this help text"
|
||||
},
|
||||
{
|
||||
'U', "usb-port", &config.usbPort,
|
||||
{ ArgOptional, ArgInt, "BOOL", { &config.usbPortArg } },
|
||||
"force serial port detection to USB if BOOL is 1 [default]\n"
|
||||
"or to RS-232 if BOOL is 0"
|
||||
},
|
||||
{
|
||||
'R', "reset", &config.reset,
|
||||
{ ArgNone },
|
||||
"reset CPU (if supported)"
|
||||
},
|
||||
{
|
||||
'a', "arduino-erase", &config.arduinoErase,
|
||||
{ ArgNone },
|
||||
"erase and reset via Arduino 1200 baud hack"
|
||||
}
|
||||
};
|
||||
|
||||
int
|
||||
help(const char* program)
|
||||
{
|
||||
fprintf(stderr, "Try '%s -h' or '%s --help' for more information\n", program, program);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static struct timeval start_time;
|
||||
|
||||
void
|
||||
timer_start()
|
||||
{
|
||||
gettimeofday(&start_time, NULL);
|
||||
}
|
||||
|
||||
float
|
||||
timer_stop()
|
||||
{
|
||||
struct timeval end;
|
||||
gettimeofday(&end, NULL);
|
||||
return (end.tv_sec - start_time.tv_sec) + (end.tv_usec - start_time.tv_usec) / 1000000.0;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char* argv[])
|
||||
{
|
||||
int args;
|
||||
char* pos;
|
||||
CmdOpts cmd(argc, argv, sizeof(opts) / sizeof(opts[0]), opts);
|
||||
|
||||
if ((pos = strrchr(argv[0], '/')) || (pos = strrchr(argv[0], '\\')))
|
||||
argv[0] = pos + 1;
|
||||
|
||||
if (argc <= 1)
|
||||
{
|
||||
fprintf(stderr, "%s: you must specify at least one option\n", argv[0]);
|
||||
return help(argv[0]);
|
||||
}
|
||||
|
||||
args = cmd.parse();
|
||||
if (args < 0)
|
||||
return help(argv[0]);
|
||||
|
||||
if (config.read && (config.write || config.verify))
|
||||
{
|
||||
fprintf(stderr, "%s: read option is exclusive of write or verify\n", argv[0]);
|
||||
return help(argv[0]);
|
||||
}
|
||||
|
||||
if (config.read || config.write || config.verify)
|
||||
{
|
||||
if (args == argc)
|
||||
{
|
||||
fprintf(stderr, "%s: missing file\n", argv[0]);
|
||||
return help(argv[0]);
|
||||
}
|
||||
argc--;
|
||||
}
|
||||
if (args != argc)
|
||||
{
|
||||
fprintf(stderr, "%s: extra arguments found\n", argv[0]);
|
||||
return help(argv[0]);
|
||||
}
|
||||
|
||||
if (config.help)
|
||||
{
|
||||
printf("Usage: %s [OPTION...] [FILE]\n", argv[0]);
|
||||
printf("Basic Open Source SAM-BA Application (BOSSA) Version " VERSION "\n"
|
||||
"Flash programmer for Atmel SAM devices.\n"
|
||||
"Copyright (c) 2011-2018 ShumaTech (http://www.shumatech.com)\n"
|
||||
"\n"
|
||||
"Examples:\n"
|
||||
" bossac -e -w -v -b image.bin # Erase flash, write flash with image.bin,\n"
|
||||
" # verify the write, and set boot from flash\n"
|
||||
" bossac -r0x10000 image.bin # Read 64KB from flash and store in image.bin\n"
|
||||
);
|
||||
printf("\nOptions:\n");
|
||||
cmd.usage(stdout);
|
||||
printf("\nReport bugs to <bugs@shumatech.com>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Samba samba;
|
||||
PortFactory portFactory;
|
||||
|
||||
if (config.debug)
|
||||
samba.setDebug(true);
|
||||
|
||||
if (!config.port)
|
||||
config.portArg = portFactory.def();
|
||||
|
||||
if (config.arduinoErase)
|
||||
{
|
||||
SerialPort::Ptr port;
|
||||
port = portFactory.create(config.portArg, config.usbPortArg != 0);
|
||||
|
||||
if(!port->open(1200))
|
||||
{
|
||||
fprintf(stderr, "Failed to open port at 1200bps\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
port->setRTS(true);
|
||||
port->setDTR(false);
|
||||
port->close();
|
||||
}
|
||||
|
||||
if (config.portArg.empty())
|
||||
{
|
||||
fprintf(stderr, "No serial ports available\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
bool res;
|
||||
if (config.usbPort)
|
||||
res = samba.connect(portFactory.create(config.portArg, config.usbPortArg != 0));
|
||||
else
|
||||
res = samba.connect(portFactory.create(config.portArg));
|
||||
if (!res)
|
||||
{
|
||||
fprintf(stderr, "No device found on %s\n", config.portArg.c_str());
|
||||
return 1;
|
||||
}
|
||||
|
||||
Device device(samba);
|
||||
device.create();
|
||||
|
||||
Device::FlashPtr& flash = device.getFlash();
|
||||
|
||||
BossaObserver observer;
|
||||
Flasher flasher(samba, device, observer);
|
||||
|
||||
if (config.info)
|
||||
{
|
||||
FlasherInfo info;
|
||||
flasher.info(info);
|
||||
info.print();
|
||||
}
|
||||
|
||||
if (config.unlock)
|
||||
flasher.lock(config.unlockArg, false);
|
||||
|
||||
if (config.erase)
|
||||
{
|
||||
timer_start();
|
||||
flasher.erase(config.offsetArg);
|
||||
printf("\nDone in %5.3f seconds\n", timer_stop());
|
||||
}
|
||||
|
||||
if (config.write)
|
||||
{
|
||||
timer_start();
|
||||
flasher.write(argv[args], config.offsetArg);
|
||||
printf("\nDone in %5.3f seconds\n", timer_stop());
|
||||
}
|
||||
|
||||
if (config.verify)
|
||||
{
|
||||
uint32_t pageErrors;
|
||||
uint32_t totalErrors;
|
||||
|
||||
timer_start();
|
||||
if (!flasher.verify(argv[args], pageErrors, totalErrors, config.offsetArg))
|
||||
{
|
||||
printf("\nVerify failed\nPage errors: %d\nByte errors: %d\n",
|
||||
pageErrors, totalErrors);
|
||||
return 2;
|
||||
}
|
||||
|
||||
printf("\nVerify successful\nDone in %5.3f seconds\n", timer_stop());
|
||||
}
|
||||
|
||||
if (config.read)
|
||||
{
|
||||
timer_start();
|
||||
flasher.read(argv[args], config.readArg, config.offsetArg);
|
||||
printf("\nDone in %5.3f seconds\n", timer_stop());
|
||||
}
|
||||
|
||||
if (config.boot)
|
||||
{
|
||||
printf("Set boot flash %s\n", config.bootArg ? "true" : "false");
|
||||
flash->setBootFlash(config.bootArg);
|
||||
}
|
||||
|
||||
if (config.bod)
|
||||
{
|
||||
printf("Set brownout detect %s\n", config.bodArg ? "true" : "false");
|
||||
flash->setBod(config.bodArg);
|
||||
}
|
||||
|
||||
if (config.bor)
|
||||
{
|
||||
printf("Set brownout reset %s\n", config.borArg ? "true" : "false");
|
||||
flash->setBor(config.borArg);
|
||||
}
|
||||
|
||||
if (config.security)
|
||||
{
|
||||
printf("Set security\n");
|
||||
flash->setSecurity();
|
||||
}
|
||||
|
||||
if (config.lock)
|
||||
flasher.lock(config.lockArg, true);
|
||||
|
||||
flash->writeOptions();
|
||||
|
||||
if (config.reset)
|
||||
device.reset();
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
fprintf(stderr, "\n%s\n", e.what());
|
||||
return 1;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
fprintf(stderr, "\nUnhandled exception\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue