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/
|
https://github.com/codazoda/hub-ctrl.c/
|
||||||
revision 42095e522859059e8a5f4ec05c1e3def01a870a9.
|
revision 42095e522859059e8a5f4ec05c1e3def01a870a9.
|
||||||
|
|
||||||
|
The bossac directory contains code from:
|
||||||
|
https://github.com/shumatech/BOSSA
|
||||||
|
version 1.9 (b176eeef918fc810045c832348590595120187b4).
|
||||||
|
|
||||||
The pru_rpmsg directory contains code from:
|
The pru_rpmsg directory contains code from:
|
||||||
https://github.com/dinuxbg/pru-gcc-examples
|
https://github.com/dinuxbg/pru-gcc-examples
|
||||||
revision 425a42d82006cf0aa24be27b483d2f6a41607489. The code is taken
|
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