From c52f6910125ab07a4d01ff2d01faf8e25fab990b Mon Sep 17 00:00:00 2001 From: "Frederic.Pillon" Date: Mon, 13 Aug 2018 14:37:18 +0200 Subject: [PATCH 1/2] [stm32flash] Remove source code The same stm32flash source code was provided for each targeted host. Source code is now provided here: https://github.com/stm32duino/stm32flash Tag: Arduino_STM32_0.9 Signed-off-by: Frederic.Pillon --- linux/src/stm32flash_serial/src/AUTHORS | 19 - linux/src/stm32flash_serial/src/Android.mk | 20 - linux/src/stm32flash_serial/src/HOWTO | 35 - linux/src/stm32flash_serial/src/I2C.txt | 94 -- linux/src/stm32flash_serial/src/Makefile | 38 - linux/src/stm32flash_serial/src/TODO | 7 - linux/src/stm32flash_serial/src/dev_table.c | 70 -- linux/src/stm32flash_serial/src/gpl-2.0.txt | 339 ------ linux/src/stm32flash_serial/src/i2c.c | 209 ---- linux/src/stm32flash_serial/src/init.c | 219 ---- linux/src/stm32flash_serial/src/init.h | 31 - linux/src/stm32flash_serial/src/main.c | 774 ------------ .../stm32flash_serial/src/parsers/Android.mk | 6 - .../stm32flash_serial/src/parsers/Makefile | 12 - .../stm32flash_serial/src/parsers/binary.c | 140 --- .../stm32flash_serial/src/parsers/binary.h | 27 - linux/src/stm32flash_serial/src/parsers/hex.c | 224 ---- linux/src/stm32flash_serial/src/parsers/hex.h | 27 - .../stm32flash_serial/src/parsers/parser.h | 56 - linux/src/stm32flash_serial/src/port.c | 59 - linux/src/stm32flash_serial/src/port.h | 75 -- linux/src/stm32flash_serial/src/protocol.txt | 19 - linux/src/stm32flash_serial/src/serial.h | 90 -- .../src/stm32flash_serial/src/serial_common.c | 154 --- .../stm32flash_serial/src/serial_platform.c | 5 - .../src/stm32flash_serial/src/serial_posix.c | 395 ------- linux/src/stm32flash_serial/src/serial_w32.c | 341 ------ linux/src/stm32flash_serial/src/stm32.c | 1048 ----------------- linux/src/stm32flash_serial/src/stm32.h | 84 -- linux/src/stm32flash_serial/src/stm32flash.1 | 407 ------- linux/src/stm32flash_serial/src/utils.c | 45 - linux/src/stm32flash_serial/src/utils.h | 30 - linux64/src/stm32flash_serial/src/AUTHORS | 19 - linux64/src/stm32flash_serial/src/Android.mk | 20 - linux64/src/stm32flash_serial/src/HOWTO | 35 - linux64/src/stm32flash_serial/src/I2C.txt | 94 -- linux64/src/stm32flash_serial/src/Makefile | 38 - linux64/src/stm32flash_serial/src/TODO | 7 - linux64/src/stm32flash_serial/src/dev_table.c | 70 -- linux64/src/stm32flash_serial/src/gpl-2.0.txt | 339 ------ linux64/src/stm32flash_serial/src/i2c.c | 209 ---- linux64/src/stm32flash_serial/src/init.c | 219 ---- linux64/src/stm32flash_serial/src/init.h | 31 - linux64/src/stm32flash_serial/src/main.c | 774 ------------ .../stm32flash_serial/src/parsers/Android.mk | 6 - .../stm32flash_serial/src/parsers/Makefile | 12 - .../stm32flash_serial/src/parsers/binary.c | 140 --- .../stm32flash_serial/src/parsers/binary.h | 27 - .../src/stm32flash_serial/src/parsers/hex.c | 224 ---- .../src/stm32flash_serial/src/parsers/hex.h | 27 - .../stm32flash_serial/src/parsers/parser.h | 56 - linux64/src/stm32flash_serial/src/port.c | 59 - linux64/src/stm32flash_serial/src/port.h | 75 -- .../src/stm32flash_serial/src/protocol.txt | 19 - linux64/src/stm32flash_serial/src/serial.h | 90 -- .../src/stm32flash_serial/src/serial_common.c | 154 --- .../stm32flash_serial/src/serial_platform.c | 5 - .../src/stm32flash_serial/src/serial_posix.c | 395 ------- .../src/stm32flash_serial/src/serial_w32.c | 341 ------ linux64/src/stm32flash_serial/src/stm32.c | 1048 ----------------- linux64/src/stm32flash_serial/src/stm32.h | 84 -- .../src/stm32flash_serial/src/stm32flash.1 | 407 ------- linux64/src/stm32flash_serial/src/utils.c | 45 - linux64/src/stm32flash_serial/src/utils.h | 30 - macosx/src/stm32flash_serial/src/AUTHORS | 19 - macosx/src/stm32flash_serial/src/Android.mk | 20 - macosx/src/stm32flash_serial/src/HOWTO | 35 - macosx/src/stm32flash_serial/src/I2C.txt | 94 -- macosx/src/stm32flash_serial/src/Makefile | 38 - macosx/src/stm32flash_serial/src/TODO | 7 - macosx/src/stm32flash_serial/src/dev_table.c | 70 -- macosx/src/stm32flash_serial/src/gpl-2.0.txt | 339 ------ macosx/src/stm32flash_serial/src/i2c.c | 209 ---- macosx/src/stm32flash_serial/src/init.c | 219 ---- macosx/src/stm32flash_serial/src/init.h | 31 - macosx/src/stm32flash_serial/src/main.c | 774 ------------ .../stm32flash_serial/src/parsers/Android.mk | 6 - .../stm32flash_serial/src/parsers/Makefile | 12 - .../stm32flash_serial/src/parsers/binary.c | 140 --- .../stm32flash_serial/src/parsers/binary.h | 27 - .../src/stm32flash_serial/src/parsers/hex.c | 224 ---- .../src/stm32flash_serial/src/parsers/hex.h | 27 - .../stm32flash_serial/src/parsers/parser.h | 56 - macosx/src/stm32flash_serial/src/port.c | 59 - macosx/src/stm32flash_serial/src/port.h | 75 -- macosx/src/stm32flash_serial/src/protocol.txt | 19 - macosx/src/stm32flash_serial/src/serial.h | 90 -- .../src/stm32flash_serial/src/serial_common.c | 154 --- .../stm32flash_serial/src/serial_platform.c | 5 - .../src/stm32flash_serial/src/serial_posix.c | 395 ------- macosx/src/stm32flash_serial/src/serial_w32.c | 341 ------ macosx/src/stm32flash_serial/src/stm32.c | 1048 ----------------- macosx/src/stm32flash_serial/src/stm32.h | 84 -- macosx/src/stm32flash_serial/src/stm32flash.1 | 407 ------- macosx/src/stm32flash_serial/src/utils.c | 45 - macosx/src/stm32flash_serial/src/utils.h | 30 - win/src/stm32flash_serial/src/AUTHORS | 19 - win/src/stm32flash_serial/src/Android.mk | 20 - win/src/stm32flash_serial/src/HOWTO | 35 - win/src/stm32flash_serial/src/I2C.txt | 94 -- win/src/stm32flash_serial/src/Makefile | 38 - win/src/stm32flash_serial/src/TODO | 7 - win/src/stm32flash_serial/src/dev_table.c | 70 -- win/src/stm32flash_serial/src/gpl-2.0.txt | 339 ------ win/src/stm32flash_serial/src/i2c.c | 209 ---- win/src/stm32flash_serial/src/init.c | 219 ---- win/src/stm32flash_serial/src/init.h | 31 - win/src/stm32flash_serial/src/main.c | 774 ------------ .../stm32flash_serial/src/parsers/Android.mk | 6 - .../stm32flash_serial/src/parsers/Makefile | 12 - .../stm32flash_serial/src/parsers/binary.c | 140 --- .../stm32flash_serial/src/parsers/binary.h | 27 - win/src/stm32flash_serial/src/parsers/hex.c | 224 ---- win/src/stm32flash_serial/src/parsers/hex.h | 27 - .../stm32flash_serial/src/parsers/parser.h | 56 - win/src/stm32flash_serial/src/port.c | 59 - win/src/stm32flash_serial/src/port.h | 75 -- win/src/stm32flash_serial/src/protocol.txt | 19 - win/src/stm32flash_serial/src/serial.h | 90 -- win/src/stm32flash_serial/src/serial_common.c | 154 --- .../stm32flash_serial/src/serial_platform.c | 5 - win/src/stm32flash_serial/src/serial_posix.c | 395 ------- win/src/stm32flash_serial/src/serial_w32.c | 341 ------ win/src/stm32flash_serial/src/stm32.c | 1048 ----------------- win/src/stm32flash_serial/src/stm32.h | 84 -- win/src/stm32flash_serial/src/stm32flash.1 | 407 ------- win/src/stm32flash_serial/src/utils.c | 45 - win/src/stm32flash_serial/src/utils.h | 30 - 128 files changed, 20396 deletions(-) delete mode 100644 linux/src/stm32flash_serial/src/AUTHORS delete mode 100644 linux/src/stm32flash_serial/src/Android.mk delete mode 100644 linux/src/stm32flash_serial/src/HOWTO delete mode 100644 linux/src/stm32flash_serial/src/I2C.txt delete mode 100644 linux/src/stm32flash_serial/src/Makefile delete mode 100644 linux/src/stm32flash_serial/src/TODO delete mode 100644 linux/src/stm32flash_serial/src/dev_table.c delete mode 100644 linux/src/stm32flash_serial/src/gpl-2.0.txt delete mode 100644 linux/src/stm32flash_serial/src/i2c.c delete mode 100644 linux/src/stm32flash_serial/src/init.c delete mode 100644 linux/src/stm32flash_serial/src/init.h delete mode 100644 linux/src/stm32flash_serial/src/main.c delete mode 100644 linux/src/stm32flash_serial/src/parsers/Android.mk delete mode 100644 linux/src/stm32flash_serial/src/parsers/Makefile delete mode 100644 linux/src/stm32flash_serial/src/parsers/binary.c delete mode 100644 linux/src/stm32flash_serial/src/parsers/binary.h delete mode 100644 linux/src/stm32flash_serial/src/parsers/hex.c delete mode 100644 linux/src/stm32flash_serial/src/parsers/hex.h delete mode 100644 linux/src/stm32flash_serial/src/parsers/parser.h delete mode 100644 linux/src/stm32flash_serial/src/port.c delete mode 100644 linux/src/stm32flash_serial/src/port.h delete mode 100644 linux/src/stm32flash_serial/src/protocol.txt delete mode 100644 linux/src/stm32flash_serial/src/serial.h delete mode 100644 linux/src/stm32flash_serial/src/serial_common.c delete mode 100644 linux/src/stm32flash_serial/src/serial_platform.c delete mode 100644 linux/src/stm32flash_serial/src/serial_posix.c delete mode 100644 linux/src/stm32flash_serial/src/serial_w32.c delete mode 100644 linux/src/stm32flash_serial/src/stm32.c delete mode 100644 linux/src/stm32flash_serial/src/stm32.h delete mode 100644 linux/src/stm32flash_serial/src/stm32flash.1 delete mode 100644 linux/src/stm32flash_serial/src/utils.c delete mode 100644 linux/src/stm32flash_serial/src/utils.h delete mode 100644 linux64/src/stm32flash_serial/src/AUTHORS delete mode 100644 linux64/src/stm32flash_serial/src/Android.mk delete mode 100644 linux64/src/stm32flash_serial/src/HOWTO delete mode 100644 linux64/src/stm32flash_serial/src/I2C.txt delete mode 100644 linux64/src/stm32flash_serial/src/Makefile delete mode 100644 linux64/src/stm32flash_serial/src/TODO delete mode 100644 linux64/src/stm32flash_serial/src/dev_table.c delete mode 100644 linux64/src/stm32flash_serial/src/gpl-2.0.txt delete mode 100644 linux64/src/stm32flash_serial/src/i2c.c delete mode 100644 linux64/src/stm32flash_serial/src/init.c delete mode 100644 linux64/src/stm32flash_serial/src/init.h delete mode 100644 linux64/src/stm32flash_serial/src/main.c delete mode 100644 linux64/src/stm32flash_serial/src/parsers/Android.mk delete mode 100644 linux64/src/stm32flash_serial/src/parsers/Makefile delete mode 100644 linux64/src/stm32flash_serial/src/parsers/binary.c delete mode 100644 linux64/src/stm32flash_serial/src/parsers/binary.h delete mode 100644 linux64/src/stm32flash_serial/src/parsers/hex.c delete mode 100644 linux64/src/stm32flash_serial/src/parsers/hex.h delete mode 100644 linux64/src/stm32flash_serial/src/parsers/parser.h delete mode 100644 linux64/src/stm32flash_serial/src/port.c delete mode 100644 linux64/src/stm32flash_serial/src/port.h delete mode 100644 linux64/src/stm32flash_serial/src/protocol.txt delete mode 100644 linux64/src/stm32flash_serial/src/serial.h delete mode 100644 linux64/src/stm32flash_serial/src/serial_common.c delete mode 100644 linux64/src/stm32flash_serial/src/serial_platform.c delete mode 100644 linux64/src/stm32flash_serial/src/serial_posix.c delete mode 100644 linux64/src/stm32flash_serial/src/serial_w32.c delete mode 100644 linux64/src/stm32flash_serial/src/stm32.c delete mode 100644 linux64/src/stm32flash_serial/src/stm32.h delete mode 100644 linux64/src/stm32flash_serial/src/stm32flash.1 delete mode 100644 linux64/src/stm32flash_serial/src/utils.c delete mode 100644 linux64/src/stm32flash_serial/src/utils.h delete mode 100644 macosx/src/stm32flash_serial/src/AUTHORS delete mode 100644 macosx/src/stm32flash_serial/src/Android.mk delete mode 100644 macosx/src/stm32flash_serial/src/HOWTO delete mode 100644 macosx/src/stm32flash_serial/src/I2C.txt delete mode 100644 macosx/src/stm32flash_serial/src/Makefile delete mode 100644 macosx/src/stm32flash_serial/src/TODO delete mode 100644 macosx/src/stm32flash_serial/src/dev_table.c delete mode 100644 macosx/src/stm32flash_serial/src/gpl-2.0.txt delete mode 100644 macosx/src/stm32flash_serial/src/i2c.c delete mode 100644 macosx/src/stm32flash_serial/src/init.c delete mode 100644 macosx/src/stm32flash_serial/src/init.h delete mode 100644 macosx/src/stm32flash_serial/src/main.c delete mode 100644 macosx/src/stm32flash_serial/src/parsers/Android.mk delete mode 100644 macosx/src/stm32flash_serial/src/parsers/Makefile delete mode 100644 macosx/src/stm32flash_serial/src/parsers/binary.c delete mode 100644 macosx/src/stm32flash_serial/src/parsers/binary.h delete mode 100644 macosx/src/stm32flash_serial/src/parsers/hex.c delete mode 100644 macosx/src/stm32flash_serial/src/parsers/hex.h delete mode 100644 macosx/src/stm32flash_serial/src/parsers/parser.h delete mode 100644 macosx/src/stm32flash_serial/src/port.c delete mode 100644 macosx/src/stm32flash_serial/src/port.h delete mode 100644 macosx/src/stm32flash_serial/src/protocol.txt delete mode 100644 macosx/src/stm32flash_serial/src/serial.h delete mode 100644 macosx/src/stm32flash_serial/src/serial_common.c delete mode 100644 macosx/src/stm32flash_serial/src/serial_platform.c delete mode 100644 macosx/src/stm32flash_serial/src/serial_posix.c delete mode 100644 macosx/src/stm32flash_serial/src/serial_w32.c delete mode 100644 macosx/src/stm32flash_serial/src/stm32.c delete mode 100644 macosx/src/stm32flash_serial/src/stm32.h delete mode 100644 macosx/src/stm32flash_serial/src/stm32flash.1 delete mode 100644 macosx/src/stm32flash_serial/src/utils.c delete mode 100644 macosx/src/stm32flash_serial/src/utils.h delete mode 100644 win/src/stm32flash_serial/src/AUTHORS delete mode 100644 win/src/stm32flash_serial/src/Android.mk delete mode 100644 win/src/stm32flash_serial/src/HOWTO delete mode 100644 win/src/stm32flash_serial/src/I2C.txt delete mode 100644 win/src/stm32flash_serial/src/Makefile delete mode 100644 win/src/stm32flash_serial/src/TODO delete mode 100644 win/src/stm32flash_serial/src/dev_table.c delete mode 100644 win/src/stm32flash_serial/src/gpl-2.0.txt delete mode 100644 win/src/stm32flash_serial/src/i2c.c delete mode 100644 win/src/stm32flash_serial/src/init.c delete mode 100644 win/src/stm32flash_serial/src/init.h delete mode 100644 win/src/stm32flash_serial/src/main.c delete mode 100644 win/src/stm32flash_serial/src/parsers/Android.mk delete mode 100644 win/src/stm32flash_serial/src/parsers/Makefile delete mode 100644 win/src/stm32flash_serial/src/parsers/binary.c delete mode 100644 win/src/stm32flash_serial/src/parsers/binary.h delete mode 100644 win/src/stm32flash_serial/src/parsers/hex.c delete mode 100644 win/src/stm32flash_serial/src/parsers/hex.h delete mode 100644 win/src/stm32flash_serial/src/parsers/parser.h delete mode 100644 win/src/stm32flash_serial/src/port.c delete mode 100644 win/src/stm32flash_serial/src/port.h delete mode 100644 win/src/stm32flash_serial/src/protocol.txt delete mode 100644 win/src/stm32flash_serial/src/serial.h delete mode 100644 win/src/stm32flash_serial/src/serial_common.c delete mode 100644 win/src/stm32flash_serial/src/serial_platform.c delete mode 100644 win/src/stm32flash_serial/src/serial_posix.c delete mode 100644 win/src/stm32flash_serial/src/serial_w32.c delete mode 100644 win/src/stm32flash_serial/src/stm32.c delete mode 100644 win/src/stm32flash_serial/src/stm32.h delete mode 100644 win/src/stm32flash_serial/src/stm32flash.1 delete mode 100644 win/src/stm32flash_serial/src/utils.c delete mode 100644 win/src/stm32flash_serial/src/utils.h diff --git a/linux/src/stm32flash_serial/src/AUTHORS b/linux/src/stm32flash_serial/src/AUTHORS deleted file mode 100644 index d096f2205..000000000 --- a/linux/src/stm32flash_serial/src/AUTHORS +++ /dev/null @@ -1,19 +0,0 @@ -Authors ordered by first contribution. - -Geoffrey McRae -Bret Olmsted -Tormod Volden -Jakob Malm -Reuben Dowle -Matthias Kubisch -Paul Fertser -Daniel Strnad -Jérémie Rapin -Christian Pointner -Mats Erik Andersson -Alexey Borovik -Antonio Borneo -Armin van der Togt -Brian Silverman -Georg Hofmann -Luis Rodrigues diff --git a/linux/src/stm32flash_serial/src/Android.mk b/linux/src/stm32flash_serial/src/Android.mk deleted file mode 100644 index 7be3d0018..000000000 --- a/linux/src/stm32flash_serial/src/Android.mk +++ /dev/null @@ -1,20 +0,0 @@ -TOP_LOCAL_PATH := $(call my-dir) - -include $(call all-named-subdir-makefiles, parsers) - -LOCAL_PATH := $(TOP_LOCAL_PATH) - -include $(CLEAR_VARS) -LOCAL_MODULE := stm32flash -LOCAL_SRC_FILES := \ - dev_table.c \ - i2c.c \ - init.c \ - main.c \ - port.c \ - serial_common.c \ - serial_platform.c \ - stm32.c \ - utils.c -LOCAL_STATIC_LIBRARIES := libparsers -include $(BUILD_EXECUTABLE) diff --git a/linux/src/stm32flash_serial/src/HOWTO b/linux/src/stm32flash_serial/src/HOWTO deleted file mode 100644 index d8f32eb04..000000000 --- a/linux/src/stm32flash_serial/src/HOWTO +++ /dev/null @@ -1,35 +0,0 @@ -Add new interfaces: -===================================================================== -Current version 0.4 supports the following interfaces: -- UART Windows (either "COMn" and "\\.\COMn"); -- UART posix/Linux (e.g. "/dev/ttyUSB0"); -- I2C Linux through standard driver "i2c-dev" (e.g. "/dev/i2c-n"). - -Starting from version 0.4, the back-end of stm32flash is modular and -ready to be expanded to support new interfaces. -I'm planning adding SPI on Linux through standard driver "spidev". -You are invited to contribute with more interfaces. - -To add a new interface you need to add a new file, populate the struct -port_interface (check at the end of files i2c.c, serial_posix.c and -serial_w32.c) and provide the relative functions to operate on the -interface: open/close, read/write, get_cfg_str and the optional gpio. -The include the new drive in Makefile and register the new struct -port_interface in file port.c in struct port_interface *ports[]. - -There are several USB-I2C adapter in the market, each providing its -own libraries to communicate with the I2C bus. -Could be interesting to provide as back-end a bridge between stm32flash -and such libraries (I have no plan on this item). - - -Add new STM32 devices: -===================================================================== -Add a new line in file dev_table.c, in table devices[]. -The fields of the table are listed in stm32.h, struct stm32_dev. - - -Cross compile on Linux host for Windows target with MinGW: -===================================================================== -I'm using a 64 bit Arch Linux machines, and I usually run: - make CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-ar diff --git a/linux/src/stm32flash_serial/src/I2C.txt b/linux/src/stm32flash_serial/src/I2C.txt deleted file mode 100644 index 4c05ff62d..000000000 --- a/linux/src/stm32flash_serial/src/I2C.txt +++ /dev/null @@ -1,94 +0,0 @@ -About I2C back-end communication in stm32flash -========================================================================== - -Starting from version v0.4, beside the serial communication port, -stm32flash adds support for I2C port to talk with STM32 bootloader. - -The current I2C back-end supports only the API provided by Linux kernel -driver "i2c-dev", so only I2C controllers with Linux kernel driver can be -used. -In Linux source code, most of the drivers for I2C and SMBUS controllers -are in - ./drivers/i2c/busses/ -Only I2C is supported by STM32 bootloader, so check the section below -about SMBUS. -No I2C support for Windows is available in stm32flash v0.4. - -Thanks to the new modular back-end, stm32flash can be easily extended to -support new back-ends and API. Check HOWTO file in stm32flash source code -for details. - -In the market there are several USB-to-I2C dongles; most of them are not -supported by kernel drivers. Manufacturer provide proprietary userspace -libraries using not standardized API. -These API and dongles could be supported in feature versions. - -There are currently 3 versions of STM32 bootloader for I2C communications: -- v1.0 using I2C clock stretching synchronization between host and STM32; -- v1.1 superset of v1.0, adds non stretching commands; -- v1.2 superset of v1.1, adds CRC command and compatibility with i2cdetect. -Details in ST application note AN2606. -All the bootloaders above are tested and working with stm32flash. - - -SMBUS controllers -========================================================================== - -Almost 50% of the drivers in Linux source code folder - ./drivers/i2c/busses/ -are for controllers that "only" support SMBUS protocol. They can NOT -operate with STM32 bootloader. -To identify if your controller supports I2C, use command: - i2cdetect -F n -where "n" is the number of the I2C interface (e.g. n=3 for "/dev/i2c-3"). -Controllers that supports I2C will report - I2C yes -Controller that support both I2C and SMBUS are ok. - -If you are interested on details about SMBUS protocol, you can download -the current specs from - http://smbus.org/specs/smbus20.pdf -and you can read the files in Linux source code - ./Documentation/i2c/i2c-protocol - ./Documentation/i2c/smbus-protocol - - -About bootloader v1.0 -========================================================================== - -Version v1.0 can have issues with some I2C controllers due to use of clock -stretching during commands that require long operations, like flash erase -and programming. - -Clock stretching is a technique to synchronize host and I2C device. When -I2C device wants to force a delay in the communication, it push "low" the -I2C clock; the I2C controller detects it and waits until I2C clock returns -"high". -Most I2C controllers set a "timeout" for clock stretching, ranging from -few milli-seconds to seconds depending on specific HW or SW driver. - -It is possible that the timeout in your I2C controller is smaller than the -delay required for flash erase or programming. In this case the I2C -controller will timeout and report error to stm32flash. -There is no possibility for stm32flash to retry, so it can only signal the -error and exit. - -To by-pass the issue with bootloader v1.0 you can modify the kernel driver -of your I2C controller. Not an easy job, since every controller has its own -way to handle the timeout. - -In my case I'm using the I2C controller integrated in the VGA port of my -laptop HP EliteBook 8460p. I built the 0.25$ VGA-to-I2C adapter reported in - http://www.paintyourdragon.com/?p=43 -To change the timeout of the I2C controller I had to modify the kernel file - drivers/gpu/drm/radeon/radeon_i2c.c -line 969 -- i2c->bit.timeout = usecs_to_jiffies(2200); /* from VESA */ -+ i2c->bit.timeout = msecs_to_jiffies(5000); /* 5s for STM32 */ -and recompile it. -Then - $> modprobe i2c-dev - $> chmod 666 /dev/i2c-7 - #> stm32flash -a 0x39 /dev/i2c-7 - -2014-09-16 Antonio Borneo diff --git a/linux/src/stm32flash_serial/src/Makefile b/linux/src/stm32flash_serial/src/Makefile deleted file mode 100644 index 0328d5588..000000000 --- a/linux/src/stm32flash_serial/src/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -PREFIX = /usr/local -CFLAGS += -Wall -g - -INSTALL = install - -OBJS = dev_table.o \ - i2c.o \ - init.o \ - main.o \ - port.o \ - serial_common.o \ - serial_platform.o \ - stm32.o \ - utils.o - -LIBOBJS = parsers/parsers.a - -all: stm32flash - -serial_platform.o: serial_posix.c serial_w32.c - -parsers/parsers.a: - cd parsers && $(MAKE) parsers.a - -stm32flash: $(OBJS) $(LIBOBJS) - $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBOBJS) - -clean: - rm -f $(OBJS) stm32flash - cd parsers && $(MAKE) $@ - -install: all - $(INSTALL) -d $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -m 755 stm32flash $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -d $(DESTDIR)$(PREFIX)/share/man/man1 - $(INSTALL) -m 644 stm32flash.1 $(DESTDIR)$(PREFIX)/share/man/man1 - -.PHONY: all clean install diff --git a/linux/src/stm32flash_serial/src/TODO b/linux/src/stm32flash_serial/src/TODO deleted file mode 100644 index 41df614ff..000000000 --- a/linux/src/stm32flash_serial/src/TODO +++ /dev/null @@ -1,7 +0,0 @@ - -stm32: -- Add support for variable page size - -AUTHORS: -- Add contributors from Geoffrey's commits - diff --git a/linux/src/stm32flash_serial/src/dev_table.c b/linux/src/stm32flash_serial/src/dev_table.c deleted file mode 100644 index 399cd9d08..000000000 --- a/linux/src/stm32flash_serial/src/dev_table.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "stm32.h" - -/* - * Device table, corresponds to the "Bootloader device-dependant parameters" - * table in ST document AN2606. - * Note that the option bytes upper range is inclusive! - */ -const stm32_dev_t devices[] = { - /* F0 */ - {0x440, "STM32F051xx" , 0x20001000, 0x20002000, 0x08000000, 0x08010000, 4, 1024, 0x1FFFF800, 0x1FFFF80B, 0x1FFFEC00, 0x1FFFF800}, - {0x444, "STM32F030/F031" , 0x20001000, 0x20002000, 0x08000000, 0x08010000, 4, 1024, 0x1FFFF800, 0x1FFFF80B, 0x1FFFEC00, 0x1FFFF800}, - {0x445, "STM32F042xx" , 0x20001800, 0x20001800, 0x08000000, 0x08008000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFC400, 0x1FFFF800}, - {0x448, "STM32F072xx" , 0x20001800, 0x20004000, 0x08000000, 0x08020000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFC800, 0x1FFFF800}, - /* F1 */ - {0x412, "Low-density" , 0x20000200, 0x20002800, 0x08000000, 0x08008000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x410, "Medium-density" , 0x20000200, 0x20005000, 0x08000000, 0x08020000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x414, "High-density" , 0x20000200, 0x20010000, 0x08000000, 0x08080000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x420, "Medium-density VL" , 0x20000200, 0x20002000, 0x08000000, 0x08020000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x428, "High-density VL" , 0x20000200, 0x20008000, 0x08000000, 0x08080000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x418, "Connectivity line" , 0x20001000, 0x20010000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFB000, 0x1FFFF800}, - {0x430, "XL-density" , 0x20000800, 0x20018000, 0x08000000, 0x08100000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFE000, 0x1FFFF800}, - /* Note that F2 and F4 devices have sectors of different page sizes - and only the first sectors (of one page size) are included here */ - /* F2 */ - {0x411, "STM32F2xx" , 0x20002000, 0x20020000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77DF}, - /* F3 */ - {0x432, "STM32F373/8" , 0x20001400, 0x20008000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - {0x422, "F302xB/303xB/358" , 0x20001400, 0x20010000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - {0x439, "STM32F302x4(6/8)" , 0x20001800, 0x20004000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - {0x438, "F303x4/334/328" , 0x20001800, 0x20003000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - /* F4 */ - {0x413, "STM32F40/1" , 0x20002000, 0x20020000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77DF}, - /* 0x419 is also used for STM32F429/39 but with other bootloader ID... */ - {0x419, "STM32F427/37" , 0x20002000, 0x20030000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF}, - {0x423, "STM32F401xB(C)" , 0x20003000, 0x20010000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF}, - {0x433, "STM32F401xD(E)" , 0x20003000, 0x20018000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF}, - /* L0 */ - {0x417, "L05xxx/06xxx" , 0x20001000, 0x20002000, 0x08000000, 0x08010000, 32, 128, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000}, - /* L1 */ - {0x416, "L1xxx6(8/B)" , 0x20000800, 0x20004000, 0x08000000, 0x08020000, 16, 256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000}, - {0x429, "L1xxx6(8/B)A" , 0x20001000, 0x20008000, 0x08000000, 0x08020000, 16, 256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000}, - {0x427, "L1xxxC" , 0x20001000, 0x20008000, 0x08000000, 0x08020000, 16, 256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF02000}, - {0x436, "L1xxxD" , 0x20001000, 0x2000C000, 0x08000000, 0x08060000, 16, 256, 0x1ff80000, 0x1ff8000F, 0x1FF00000, 0x1FF02000}, - {0x437, "L1xxxE" , 0x20001000, 0x20014000, 0x08000000, 0x08060000, 16, 256, 0x1ff80000, 0x1ff8000F, 0x1FF00000, 0x1FF02000}, - /* These are not (yet) in AN2606: */ - {0x641, "Medium_Density PL" , 0x20000200, 0x00005000, 0x08000000, 0x08020000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x9a8, "STM32W-128K" , 0x20000200, 0x20002000, 0x08000000, 0x08020000, 1, 1024, 0, 0, 0, 0}, - {0x9b0, "STM32W-256K" , 0x20000200, 0x20004000, 0x08000000, 0x08040000, 1, 2048, 0, 0, 0, 0}, - {0x0} -}; diff --git a/linux/src/stm32flash_serial/src/gpl-2.0.txt b/linux/src/stm32flash_serial/src/gpl-2.0.txt deleted file mode 100644 index d159169d1..000000000 --- a/linux/src/stm32flash_serial/src/gpl-2.0.txt +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 2 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, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/linux/src/stm32flash_serial/src/i2c.c b/linux/src/stm32flash_serial/src/i2c.c deleted file mode 100644 index 10e6bb15a..000000000 --- a/linux/src/stm32flash_serial/src/i2c.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "serial.h" -#include "port.h" - - -#if !defined(__linux__) - -static port_err_t i2c_open(struct port_interface *port, - struct port_options *ops) -{ - return PORT_ERR_NODEV; -} - -struct port_interface port_i2c = { - .name = "i2c", - .open = i2c_open, -}; - -#else - -#ifdef __ANDROID__ -#define I2C_SLAVE 0x0703 /* Use this slave address */ -#define I2C_FUNCS 0x0705 /* Get the adapter functionality mask */ -/* To determine what functionality is present */ -#define I2C_FUNC_I2C 0x00000001 -#else -#include -#include -#endif - -#include - -struct i2c_priv { - int fd; - int addr; -}; - -static port_err_t i2c_open(struct port_interface *port, - struct port_options *ops) -{ - struct i2c_priv *h; - int fd, addr, ret; - unsigned long funcs; - - /* 1. check device name match */ - if (strncmp(ops->device, "/dev/i2c-", strlen("/dev/i2c-"))) - return PORT_ERR_NODEV; - - /* 2. check options */ - addr = ops->bus_addr; - if (addr < 0x03 || addr > 0x77) { - fprintf(stderr, "I2C address out of range [0x03-0x77]\n"); - return PORT_ERR_UNKNOWN; - } - - /* 3. open it */ - h = calloc(sizeof(*h), 1); - if (h == NULL) { - fprintf(stderr, "End of memory\n"); - return PORT_ERR_UNKNOWN; - } - fd = open(ops->device, O_RDWR); - if (fd < 0) { - fprintf(stderr, "Unable to open special file \"%s\"\n", - ops->device); - free(h); - return PORT_ERR_UNKNOWN; - } - - /* 3.5. Check capabilities */ - ret = ioctl(fd, I2C_FUNCS, &funcs); - if (ret < 0) { - fprintf(stderr, "I2C ioctl(funcs) error %d\n", errno); - close(fd); - free(h); - return PORT_ERR_UNKNOWN; - } - if ((funcs & I2C_FUNC_I2C) == 0) { - fprintf(stderr, "Error: controller is not I2C, only SMBUS.\n"); - close(fd); - free(h); - return PORT_ERR_UNKNOWN; - } - - /* 4. set options */ - ret = ioctl(fd, I2C_SLAVE, addr); - if (ret < 0) { - fprintf(stderr, "I2C ioctl(slave) error %d\n", errno); - close(fd); - free(h); - return PORT_ERR_UNKNOWN; - } - - h->fd = fd; - h->addr = addr; - port->private = h; - return PORT_ERR_OK; -} - -static port_err_t i2c_close(struct port_interface *port) -{ - struct i2c_priv *h; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - close(h->fd); - free(h); - port->private = NULL; - return PORT_ERR_OK; -} - -static port_err_t i2c_read(struct port_interface *port, void *buf, - size_t nbyte) -{ - struct i2c_priv *h; - int ret; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - ret = read(h->fd, buf, nbyte); - if (ret != nbyte) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; -} - -static port_err_t i2c_write(struct port_interface *port, void *buf, - size_t nbyte) -{ - struct i2c_priv *h; - int ret; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - ret = write(h->fd, buf, nbyte); - if (ret != nbyte) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; -} - -static port_err_t i2c_gpio(struct port_interface *port, serial_gpio_t n, - int level) -{ - return PORT_ERR_OK; -} - -static const char *i2c_get_cfg_str(struct port_interface *port) -{ - struct i2c_priv *h; - static char str[11]; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return "INVALID"; - snprintf(str, sizeof(str), "addr 0x%2x", h->addr); - return str; -} - -static struct varlen_cmd i2c_cmd_get_reply[] = { - {0x10, 11}, - {0x11, 17}, - {0x12, 18}, - { /* sentinel */ } -}; - -struct port_interface port_i2c = { - .name = "i2c", - .flags = PORT_STRETCH_W, - .open = i2c_open, - .close = i2c_close, - .read = i2c_read, - .write = i2c_write, - .gpio = i2c_gpio, - .cmd_get_reply = i2c_cmd_get_reply, - .get_cfg_str = i2c_get_cfg_str, -}; - -#endif diff --git a/linux/src/stm32flash_serial/src/init.c b/linux/src/stm32flash_serial/src/init.c deleted file mode 100644 index 77a571bd8..000000000 --- a/linux/src/stm32flash_serial/src/init.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2013 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "init.h" -#include "serial.h" -#include "stm32.h" -#include "port.h" - -struct gpio_list { - struct gpio_list *next; - int gpio; -}; - - -static int write_to(const char *filename, const char *value) -{ - int fd, ret; - - fd = open(filename, O_WRONLY); - if (fd < 0) { - fprintf(stderr, "Cannot open file \"%s\"\n", filename); - return 0; - } - ret = write(fd, value, strlen(value)); - if (ret < 0) { - fprintf(stderr, "Error writing in file \"%s\"\n", filename); - close(fd); - return 0; - } - close(fd); - return 1; -} - -#if !defined(__linux__) -static int drive_gpio(int n, int level, struct gpio_list **gpio_to_release) -{ - fprintf(stderr, "GPIO control only available in Linux\n"); - return 0; -} -#else -static int drive_gpio(int n, int level, struct gpio_list **gpio_to_release) -{ - char num[16]; /* sized to carry MAX_INT */ - char file[48]; /* sized to carry longest filename */ - struct stat buf; - struct gpio_list *new; - int ret; - - sprintf(file, "/sys/class/gpio/gpio%d/direction", n); - ret = stat(file, &buf); - if (ret) { - /* file miss, GPIO not exported yet */ - sprintf(num, "%d", n); - ret = write_to("/sys/class/gpio/export", num); - if (!ret) - return 0; - ret = stat(file, &buf); - if (ret) { - fprintf(stderr, "GPIO %d not available\n", n); - return 0; - } - new = (struct gpio_list *)malloc(sizeof(struct gpio_list)); - if (new == NULL) { - fprintf(stderr, "Out of memory\n"); - return 0; - } - new->gpio = n; - new->next = *gpio_to_release; - *gpio_to_release = new; - } - - return write_to(file, level ? "high" : "low"); -} -#endif - -static int release_gpio(int n) -{ - char num[16]; /* sized to carry MAX_INT */ - - sprintf(num, "%d", n); - return write_to("/sys/class/gpio/unexport", num); -} - -static int gpio_sequence(struct port_interface *port, const char *s, size_t l) -{ - struct gpio_list *gpio_to_release = NULL, *to_free; - int ret, level, gpio; - - ret = 1; - while (ret == 1 && *s && l > 0) { - if (*s == '-') { - level = 0; - s++; - l--; - } else - level = 1; - - if (isdigit(*s)) { - gpio = atoi(s); - while (isdigit(*s)) { - s++; - l--; - } - } else if (!strncmp(s, "rts", 3)) { - gpio = -GPIO_RTS; - s += 3; - l -= 3; - } else if (!strncmp(s, "dtr", 3)) { - gpio = -GPIO_DTR; - s += 3; - l -= 3; - } else if (!strncmp(s, "brk", 3)) { - gpio = -GPIO_BRK; - s += 3; - l -= 3; - } else { - fprintf(stderr, "Character \'%c\' is not a digit\n", *s); - ret = 0; - break; - } - - if (*s && (l > 0)) { - if (*s == ',') { - s++; - l--; - } else { - fprintf(stderr, "Character \'%c\' is not a separator\n", *s); - ret = 0; - break; - } - } - if (gpio < 0) - ret = (port->gpio(port, -gpio, level) == PORT_ERR_OK); - else - ret = drive_gpio(gpio, level, &gpio_to_release); - usleep(100000); - } - - while (gpio_to_release) { - release_gpio(gpio_to_release->gpio); - to_free = gpio_to_release; - gpio_to_release = gpio_to_release->next; - free(to_free); - } - usleep(500000); - return ret; -} - -static int gpio_bl_entry(struct port_interface *port, const char *seq) -{ - char *s; - - if (seq == NULL || seq[0] == ':') - return 1; - - s = strchr(seq, ':'); - if (s == NULL) - return gpio_sequence(port, seq, strlen(seq)); - - return gpio_sequence(port, seq, s - seq); -} - -static int gpio_bl_exit(struct port_interface *port, const char *seq) -{ - char *s; - - if (seq == NULL) - return 1; - - s = strchr(seq, ':'); - if (s == NULL || s[1] == '\0') - return 1; - - return gpio_sequence(port, s + 1, strlen(s + 1)); -} - -int init_bl_entry(struct port_interface *port, const char *seq) -{ - if (seq) - return gpio_bl_entry(port, seq); - - return 1; -} - -int init_bl_exit(stm32_t *stm, struct port_interface *port, const char *seq) -{ - if (seq) - return gpio_bl_exit(port, seq); - - if (stm32_reset_device(stm) != STM32_ERR_OK) - return 0; - return 1; -} diff --git a/linux/src/stm32flash_serial/src/init.h b/linux/src/stm32flash_serial/src/init.h deleted file mode 100644 index 6075b519b..000000000 --- a/linux/src/stm32flash_serial/src/init.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2013 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _INIT_H -#define _INIT_H - -#include "stm32.h" -#include "port.h" - -int init_bl_entry(struct port_interface *port, const char *seq); -int init_bl_exit(stm32_t *stm, struct port_interface *port, const char *seq); - -#endif diff --git a/linux/src/stm32flash_serial/src/main.c b/linux/src/stm32flash_serial/src/main.c deleted file mode 100644 index f081d6131..000000000 --- a/linux/src/stm32flash_serial/src/main.c +++ /dev/null @@ -1,774 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright 2010 Geoffrey McRae - Copyright 2011 Steve Markgraf - Copyright 2012 Tormod Volden - Copyright 2013 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "init.h" -#include "utils.h" -#include "serial.h" -#include "stm32.h" -#include "parsers/parser.h" -#include "port.h" - -#include "parsers/binary.h" -#include "parsers/hex.h" - -#define VERSION "Arduino_STM32_0.9" - -/* device globals */ -stm32_t *stm = NULL; - -void *p_st = NULL; -parser_t *parser = NULL; - -/* settings */ -struct port_options port_opts = { - .device = NULL, - .baudRate = SERIAL_BAUD_57600, - .serial_mode = "8e1", - .bus_addr = 0, - .rx_frame_max = STM32_MAX_RX_FRAME, - .tx_frame_max = STM32_MAX_TX_FRAME, -}; -int rd = 0; -int wr = 0; -int wu = 0; -int rp = 0; -int ur = 0; -int eraseOnly = 0; -int crc = 0; -int npages = 0; -int spage = 0; -int no_erase = 0; -char verify = 0; -int retry = 10; -char exec_flag = 0; -uint32_t execute = 0; -char init_flag = 1; -char force_binary = 0; -char reset_flag = 0; -char *filename; -char *gpio_seq = NULL; -uint32_t start_addr = 0; -uint32_t readwrite_len = 0; - -/* functions */ -int parse_options(int argc, char *argv[]); -void show_help(char *name); - -static int is_addr_in_ram(uint32_t addr) -{ - return addr >= stm->dev->ram_start && addr < stm->dev->ram_end; -} - -static int is_addr_in_flash(uint32_t addr) -{ - return addr >= stm->dev->fl_start && addr < stm->dev->fl_end; -} - -static int flash_addr_to_page_floor(uint32_t addr) -{ - if (!is_addr_in_flash(addr)) - return 0; - - return (addr - stm->dev->fl_start) / stm->dev->fl_ps; -} - -static int flash_addr_to_page_ceil(uint32_t addr) -{ - if (!(addr >= stm->dev->fl_start && addr <= stm->dev->fl_end)) - return 0; - - return (addr + stm->dev->fl_ps - 1 - stm->dev->fl_start) - / stm->dev->fl_ps; -} - -static uint32_t flash_page_to_addr(int page) -{ - return stm->dev->fl_start + page * stm->dev->fl_ps; -} - -int main(int argc, char* argv[]) { - struct port_interface *port = NULL; - int ret = 1; - stm32_err_t s_err; - parser_err_t perr; - FILE *diag = stdout; - - fprintf(diag, "stm32flash " VERSION "\n\n"); - fprintf(diag, "http://github.com/rogerclarkmelbourne/arduino_stm32\n\n"); - if (parse_options(argc, argv) != 0) - goto close; - - if (rd && filename[0] == '-') { - diag = stderr; - } - - if (wr) { - /* first try hex */ - if (!force_binary) { - parser = &PARSER_HEX; - p_st = parser->init(); - if (!p_st) { - fprintf(stderr, "%s Parser failed to initialize\n", parser->name); - goto close; - } - } - - if (force_binary || (perr = parser->open(p_st, filename, 0)) != PARSER_ERR_OK) { - if (force_binary || perr == PARSER_ERR_INVALID_FILE) { - if (!force_binary) { - parser->close(p_st); - p_st = NULL; - } - - /* now try binary */ - parser = &PARSER_BINARY; - p_st = parser->init(); - if (!p_st) { - fprintf(stderr, "%s Parser failed to initialize\n", parser->name); - goto close; - } - perr = parser->open(p_st, filename, 0); - } - - /* if still have an error, fail */ - if (perr != PARSER_ERR_OK) { - fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr)); - if (perr == PARSER_ERR_SYSTEM) perror(filename); - goto close; - } - } - - fprintf(diag, "Using Parser : %s\n", parser->name); - } else { - parser = &PARSER_BINARY; - p_st = parser->init(); - if (!p_st) { - fprintf(stderr, "%s Parser failed to initialize\n", parser->name); - goto close; - } - } - - if (port_open(&port_opts, &port) != PORT_ERR_OK) { - fprintf(stderr, "Failed to open port: %s\n", port_opts.device); - goto close; - } - - fprintf(diag, "Interface %s: %s\n", port->name, port->get_cfg_str(port)); - if (init_flag && init_bl_entry(port, gpio_seq) == 0) - goto close; - stm = stm32_init(port, init_flag); - if (!stm) - goto close; - - fprintf(diag, "Version : 0x%02x\n", stm->bl_version); - if (port->flags & PORT_GVR_ETX) { - fprintf(diag, "Option 1 : 0x%02x\n", stm->option1); - fprintf(diag, "Option 2 : 0x%02x\n", stm->option2); - } - fprintf(diag, "Device ID : 0x%04x (%s)\n", stm->pid, stm->dev->name); - fprintf(diag, "- RAM : %dKiB (%db reserved by bootloader)\n", (stm->dev->ram_end - 0x20000000) / 1024, stm->dev->ram_start - 0x20000000); - fprintf(diag, "- Flash : %dKiB (sector size: %dx%d)\n", (stm->dev->fl_end - stm->dev->fl_start ) / 1024, stm->dev->fl_pps, stm->dev->fl_ps); - fprintf(diag, "- Option RAM : %db\n", stm->dev->opt_end - stm->dev->opt_start + 1); - fprintf(diag, "- System RAM : %dKiB\n", (stm->dev->mem_end - stm->dev->mem_start) / 1024); - - uint8_t buffer[256]; - uint32_t addr, start, end; - unsigned int len; - int failed = 0; - int first_page, num_pages; - - /* - * Cleanup addresses: - * - * Starting from options - * start_addr, readwrite_len, spage, npages - * and using device memory size, compute - * start, end, first_page, num_pages - */ - if (start_addr || readwrite_len) { - start = start_addr; - - if (is_addr_in_flash(start)) - end = stm->dev->fl_end; - else { - no_erase = 1; - if (is_addr_in_ram(start)) - end = stm->dev->ram_end; - else - end = start + sizeof(uint32_t); - } - - if (readwrite_len && (end > start + readwrite_len)) - end = start + readwrite_len; - - first_page = flash_addr_to_page_floor(start); - if (!first_page && end == stm->dev->fl_end) - num_pages = 0xff; /* mass erase */ - else - num_pages = flash_addr_to_page_ceil(end) - first_page; - } else if (!spage && !npages) { - start = stm->dev->fl_start; - end = stm->dev->fl_end; - first_page = 0; - num_pages = 0xff; /* mass erase */ - } else { - first_page = spage; - start = flash_page_to_addr(first_page); - if (start > stm->dev->fl_end) { - fprintf(stderr, "Address range exceeds flash size.\n"); - goto close; - } - - if (npages) { - num_pages = npages; - end = flash_page_to_addr(first_page + num_pages); - if (end > stm->dev->fl_end) - end = stm->dev->fl_end; - } else { - end = stm->dev->fl_end; - num_pages = flash_addr_to_page_ceil(end) - first_page; - } - - if (!first_page && end == stm->dev->fl_end) - num_pages = 0xff; /* mass erase */ - } - - if (rd) { - unsigned int max_len = port_opts.rx_frame_max; - - fprintf(diag, "Memory read\n"); - - perr = parser->open(p_st, filename, 1); - if (perr != PARSER_ERR_OK) { - fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr)); - if (perr == PARSER_ERR_SYSTEM) - perror(filename); - goto close; - } - - fflush(diag); - addr = start; - while(addr < end) { - uint32_t left = end - addr; - len = max_len > left ? left : max_len; - s_err = stm32_read_memory(stm, addr, buffer, len); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to read memory at address 0x%08x, target write-protected?\n", addr); - goto close; - } - if (parser->write(p_st, buffer, len) != PARSER_ERR_OK) - { - fprintf(stderr, "Failed to write data to file\n"); - goto close; - } - addr += len; - - fprintf(diag, - "\rRead address 0x%08x (%.2f%%) ", - addr, - (100.0f / (float)(end - start)) * (float)(addr - start) - ); - fflush(diag); - } - fprintf(diag, "Done.\n"); - ret = 0; - goto close; - } else if (rp) { - fprintf(stdout, "Read-Protecting flash\n"); - /* the device automatically performs a reset after the sending the ACK */ - reset_flag = 0; - stm32_readprot_memory(stm); - fprintf(stdout, "Done.\n"); - } else if (ur) { - fprintf(stdout, "Read-UnProtecting flash\n"); - /* the device automatically performs a reset after the sending the ACK */ - reset_flag = 0; - stm32_runprot_memory(stm); - fprintf(stdout, "Done.\n"); - } else if (eraseOnly) { - ret = 0; - fprintf(stdout, "Erasing flash\n"); - - if (num_pages != 0xff && - (start != flash_page_to_addr(first_page) - || end != flash_page_to_addr(first_page + num_pages))) { - fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n"); - ret = 1; - goto close; - } - - s_err = stm32_erase_memory(stm, first_page, num_pages); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to erase memory\n"); - ret = 1; - goto close; - } - } else if (wu) { - fprintf(diag, "Write-unprotecting flash\n"); - /* the device automatically performs a reset after the sending the ACK */ - reset_flag = 0; - stm32_wunprot_memory(stm); - fprintf(diag, "Done.\n"); - - } else if (wr) { - fprintf(diag, "Write to memory\n"); - - off_t offset = 0; - ssize_t r; - unsigned int size; - unsigned int max_wlen, max_rlen; - - max_wlen = port_opts.tx_frame_max - 2; /* skip len and crc */ - max_wlen &= ~3; /* 32 bit aligned */ - - max_rlen = port_opts.rx_frame_max; - max_rlen = max_rlen < max_wlen ? max_rlen : max_wlen; - - /* Assume data from stdin is whole device */ - if (filename[0] == '-' && filename[1] == '\0') - size = end - start; - else - size = parser->size(p_st); - - // TODO: It is possible to write to non-page boundaries, by reading out flash - // from partial pages and combining with the input data - // if ((start % stm->dev->fl_ps) != 0 || (end % stm->dev->fl_ps) != 0) { - // fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n"); - // goto close; - // } - - // TODO: If writes are not page aligned, we should probably read out existing flash - // contents first, so it can be preserved and combined with new data - if (!no_erase && num_pages) { - fprintf(diag, "Erasing memory\n"); - s_err = stm32_erase_memory(stm, first_page, num_pages); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to erase memory\n"); - goto close; - } - } - - fflush(diag); - addr = start; - while(addr < end && offset < size) { - uint32_t left = end - addr; - len = max_wlen > left ? left : max_wlen; - len = len > size - offset ? size - offset : len; - - if (parser->read(p_st, buffer, &len) != PARSER_ERR_OK) - goto close; - - if (len == 0) { - if (filename[0] == '-') { - break; - } else { - fprintf(stderr, "Failed to read input file\n"); - goto close; - } - } - - again: - s_err = stm32_write_memory(stm, addr, buffer, len); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to write memory at address 0x%08x\n", addr); - goto close; - } - - if (verify) { - uint8_t compare[len]; - unsigned int offset, rlen; - - offset = 0; - while (offset < len) { - rlen = len - offset; - rlen = rlen < max_rlen ? rlen : max_rlen; - s_err = stm32_read_memory(stm, addr + offset, compare + offset, rlen); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to read memory at address 0x%08x\n", addr + offset); - goto close; - } - offset += rlen; - } - - for(r = 0; r < len; ++r) - if (buffer[r] != compare[r]) { - if (failed == retry) { - fprintf(stderr, "Failed to verify at address 0x%08x, expected 0x%02x and found 0x%02x\n", - (uint32_t)(addr + r), - buffer [r], - compare[r] - ); - goto close; - } - ++failed; - goto again; - } - - failed = 0; - } - - addr += len; - offset += len; - - fprintf(diag, - "\rWrote %saddress 0x%08x (%.2f%%) ", - verify ? "and verified " : "", - addr, - (100.0f / size) * offset - ); - fflush(diag); - - } - - fprintf(diag, "Done.\n"); - ret = 0; - goto close; - } else if (crc) { - uint32_t crc_val = 0; - - fprintf(diag, "CRC computation\n"); - - s_err = stm32_crc_wrapper(stm, start, end - start, &crc_val); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to read CRC\n"); - goto close; - } - fprintf(diag, "CRC(0x%08x-0x%08x) = 0x%08x\n", start, end, - crc_val); - ret = 0; - goto close; - } else - ret = 0; - -close: - if (stm && exec_flag && ret == 0) { - if (execute == 0) - execute = stm->dev->fl_start; - - fprintf(diag, "\nStarting execution at address 0x%08x... ", execute); - fflush(diag); - if (stm32_go(stm, execute) == STM32_ERR_OK) { - reset_flag = 0; - fprintf(diag, "done.\n"); - } else - fprintf(diag, "failed.\n"); - } - - if (stm && reset_flag) { - fprintf(diag, "\nResetting device... "); - fflush(diag); - if (init_bl_exit(stm, port, gpio_seq)) - fprintf(diag, "done.\n"); - else fprintf(diag, "failed.\n"); - } - - if (p_st ) parser->close(p_st); - if (stm ) stm32_close (stm); - if (port) - port->close(port); - - fprintf(diag, "\n"); - return ret; -} - -int parse_options(int argc, char *argv[]) -{ - int c; - char *pLen; - - while ((c = getopt(argc, argv, "a:b:m:r:w:e:vn:g:jkfcChuos:S:F:i:R")) != -1) { - switch(c) { - case 'a': - port_opts.bus_addr = strtoul(optarg, NULL, 0); - break; - - case 'b': - port_opts.baudRate = serial_get_baud(strtoul(optarg, NULL, 0)); - if (port_opts.baudRate == SERIAL_BAUD_INVALID) { - serial_baud_t baudrate; - fprintf(stderr, "Invalid baud rate, valid options are:\n"); - for (baudrate = SERIAL_BAUD_1200; baudrate != SERIAL_BAUD_INVALID; ++baudrate) - fprintf(stderr, " %d\n", serial_get_baud_int(baudrate)); - return 1; - } - break; - - case 'm': - if (strlen(optarg) != 3 - || serial_get_bits(optarg) == SERIAL_BITS_INVALID - || serial_get_parity(optarg) == SERIAL_PARITY_INVALID - || serial_get_stopbit(optarg) == SERIAL_STOPBIT_INVALID) { - fprintf(stderr, "Invalid serial mode\n"); - return 1; - } - port_opts.serial_mode = optarg; - break; - - case 'r': - case 'w': - rd = rd || c == 'r'; - wr = wr || c == 'w'; - if (rd && wr) { - fprintf(stderr, "ERROR: Invalid options, can't read & write at the same time\n"); - return 1; - } - filename = optarg; - if (filename[0] == '-') { - force_binary = 1; - } - break; - case 'e': - if (readwrite_len || start_addr) { - fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n"); - return 1; - } - npages = strtoul(optarg, NULL, 0); - if (npages > 0xFF || npages < 0) { - fprintf(stderr, "ERROR: You need to specify a page count between 0 and 255"); - return 1; - } - if (!npages) - no_erase = 1; - break; - case 'u': - wu = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't write unprotect and read/write at the same time\n"); - return 1; - } - break; - - case 'j': - rp = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't read protect and read/write at the same time\n"); - return 1; - } - break; - - case 'k': - ur = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't read unprotect and read/write at the same time\n"); - return 1; - } - break; - - case 'o': - eraseOnly = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't erase-only and read/write at the same time\n"); - return 1; - } - break; - - case 'v': - verify = 1; - break; - - case 'n': - retry = strtoul(optarg, NULL, 0); - break; - - case 'g': - exec_flag = 1; - execute = strtoul(optarg, NULL, 0); - if (execute % 4 != 0) { - fprintf(stderr, "ERROR: Execution address must be word-aligned\n"); - return 1; - } - break; - case 's': - if (readwrite_len || start_addr) { - fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n"); - return 1; - } - spage = strtoul(optarg, NULL, 0); - break; - case 'S': - if (spage || npages) { - fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n"); - return 1; - } else { - start_addr = strtoul(optarg, &pLen, 0); - if (*pLen == ':') { - pLen++; - readwrite_len = strtoul(pLen, NULL, 0); - if (readwrite_len == 0) { - fprintf(stderr, "ERROR: Invalid options, can't specify zero length\n"); - return 1; - } - } - } - break; - case 'F': - port_opts.rx_frame_max = strtoul(optarg, &pLen, 0); - if (*pLen == ':') { - pLen++; - port_opts.tx_frame_max = strtoul(pLen, NULL, 0); - } - if (port_opts.rx_frame_max < 0 - || port_opts.tx_frame_max < 0) { - fprintf(stderr, "ERROR: Invalid negative value for option -F\n"); - return 1; - } - if (port_opts.rx_frame_max == 0) - port_opts.rx_frame_max = STM32_MAX_RX_FRAME; - if (port_opts.tx_frame_max == 0) - port_opts.tx_frame_max = STM32_MAX_TX_FRAME; - if (port_opts.rx_frame_max < 20 - || port_opts.tx_frame_max < 5) { - fprintf(stderr, "ERROR: current code cannot work with small frames.\n"); - fprintf(stderr, "min(RX) = 20, min(TX) = 5\n"); - return 1; - } - if (port_opts.rx_frame_max > STM32_MAX_RX_FRAME) { - fprintf(stderr, "WARNING: Ignore RX length in option -F\n"); - port_opts.rx_frame_max = STM32_MAX_RX_FRAME; - } - if (port_opts.tx_frame_max > STM32_MAX_TX_FRAME) { - fprintf(stderr, "WARNING: Ignore TX length in option -F\n"); - port_opts.tx_frame_max = STM32_MAX_TX_FRAME; - } - break; - case 'f': - force_binary = 1; - break; - - case 'c': - init_flag = 0; - break; - - case 'h': - show_help(argv[0]); - exit(0); - - case 'i': - gpio_seq = optarg; - break; - - case 'R': - reset_flag = 1; - break; - - case 'C': - crc = 1; - break; - } - } - - for (c = optind; c < argc; ++c) { - if (port_opts.device) { - fprintf(stderr, "ERROR: Invalid parameter specified\n"); - show_help(argv[0]); - return 1; - } - port_opts.device = argv[c]; - } - - if (port_opts.device == NULL) { - fprintf(stderr, "ERROR: Device not specified\n"); - show_help(argv[0]); - return 1; - } - - if (!wr && verify) { - fprintf(stderr, "ERROR: Invalid usage, -v is only valid when writing\n"); - show_help(argv[0]); - return 1; - } - - return 0; -} - -void show_help(char *name) { - fprintf(stderr, - "Usage: %s [-bvngfhc] [-[rw] filename] [tty_device | i2c_device]\n" - " -a bus_address Bus address (e.g. for I2C port)\n" - " -b rate Baud rate (default 57600)\n" - " -m mode Serial port mode (default 8e1)\n" - " -r filename Read flash to file (or - stdout)\n" - " -w filename Write flash from file (or - stdout)\n" - " -C Compute CRC of flash content\n" - " -u Disable the flash write-protection\n" - " -j Enable the flash read-protection\n" - " -k Disable the flash read-protection\n" - " -o Erase only\n" - " -e n Only erase n pages before writing the flash\n" - " -v Verify writes\n" - " -n count Retry failed writes up to count times (default 10)\n" - " -g address Start execution at specified address (0 = flash start)\n" - " -S address[:length] Specify start address and optionally length for\n" - " read/write/erase operations\n" - " -F RX_length[:TX_length] Specify the max length of RX and TX frame\n" - " -s start_page Flash at specified page (0 = flash start)\n" - " -f Force binary parser\n" - " -h Show this help\n" - " -c Resume the connection (don't send initial INIT)\n" - " *Baud rate must be kept the same as the first init*\n" - " This is useful if the reset fails\n" - " -i GPIO_string GPIO sequence to enter/exit bootloader mode\n" - " GPIO_string=[entry_seq][:[exit_seq]]\n" - " sequence=[-]n[,sequence]\n" - " -R Reset device at exit.\n" - "\n" - "Examples:\n" - " Get device information:\n" - " %s /dev/ttyS0\n" - " or:\n" - " %s /dev/i2c-0\n" - "\n" - " Write with verify and then start execution:\n" - " %s -w filename -v -g 0x0 /dev/ttyS0\n" - "\n" - " Read flash to file:\n" - " %s -r filename /dev/ttyS0\n" - "\n" - " Read 100 bytes of flash from 0x1000 to stdout:\n" - " %s -r - -S 0x1000:100 /dev/ttyS0\n" - "\n" - " Start execution:\n" - " %s -g 0x0 /dev/ttyS0\n" - "\n" - " GPIO sequence:\n" - " - entry sequence: GPIO_3=low, GPIO_2=low, GPIO_2=high\n" - " - exit sequence: GPIO_3=high, GPIO_2=low, GPIO_2=high\n" - " %s -i -3,-2,2:3,-2,2 /dev/ttyS0\n", - name, - name, - name, - name, - name, - name, - name, - name - ); -} - diff --git a/linux/src/stm32flash_serial/src/parsers/Android.mk b/linux/src/stm32flash_serial/src/parsers/Android.mk deleted file mode 100644 index afec18cd5..000000000 --- a/linux/src/stm32flash_serial/src/parsers/Android.mk +++ /dev/null @@ -1,6 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := libparsers -LOCAL_SRC_FILES := binary.c hex.c -include $(BUILD_STATIC_LIBRARY) diff --git a/linux/src/stm32flash_serial/src/parsers/Makefile b/linux/src/stm32flash_serial/src/parsers/Makefile deleted file mode 100644 index bb7df1e02..000000000 --- a/linux/src/stm32flash_serial/src/parsers/Makefile +++ /dev/null @@ -1,12 +0,0 @@ - -CFLAGS += -Wall -g - -all: parsers.a - -parsers.a: binary.o hex.o - $(AR) rc $@ binary.o hex.o - -clean: - rm -f *.o parsers.a - -.PHONY: all clean diff --git a/linux/src/stm32flash_serial/src/parsers/binary.c b/linux/src/stm32flash_serial/src/parsers/binary.c deleted file mode 100644 index f491952bb..000000000 --- a/linux/src/stm32flash_serial/src/parsers/binary.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include - -#include "binary.h" - -typedef struct { - int fd; - char write; - struct stat stat; -} binary_t; - -void* binary_init() { - return calloc(sizeof(binary_t), 1); -} - -parser_err_t binary_open(void *storage, const char *filename, const char write) { - binary_t *st = storage; - if (write) { - if (filename[0] == '-') - st->fd = 1; - else - st->fd = open( - filename, -#ifndef __WIN32__ - O_WRONLY | O_CREAT | O_TRUNC, -#else - O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, -#endif -#ifndef __WIN32__ - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH -#else - 0 -#endif - ); - st->stat.st_size = 0; - } else { - if (filename[0] == '-') { - st->fd = 0; - } else { - if (stat(filename, &st->stat) != 0) - return PARSER_ERR_INVALID_FILE; - st->fd = open(filename, -#ifndef __WIN32__ - O_RDONLY -#else - O_RDONLY | O_BINARY -#endif - ); - } - } - - st->write = write; - return st->fd == -1 ? PARSER_ERR_SYSTEM : PARSER_ERR_OK; -} - -parser_err_t binary_close(void *storage) { - binary_t *st = storage; - - if (st->fd) close(st->fd); - free(st); - return PARSER_ERR_OK; -} - -unsigned int binary_size(void *storage) { - binary_t *st = storage; - return st->stat.st_size; -} - -parser_err_t binary_read(void *storage, void *data, unsigned int *len) { - binary_t *st = storage; - unsigned int left = *len; - if (st->write) return PARSER_ERR_WRONLY; - - ssize_t r; - while(left > 0) { - r = read(st->fd, data, left); - /* If there is no data to read at all, return OK, but with zero read */ - if (r == 0 && left == *len) { - *len = 0; - return PARSER_ERR_OK; - } - if (r <= 0) return PARSER_ERR_SYSTEM; - left -= r; - data += r; - } - - *len = *len - left; - return PARSER_ERR_OK; -} - -parser_err_t binary_write(void *storage, void *data, unsigned int len) { - binary_t *st = storage; - if (!st->write) return PARSER_ERR_RDONLY; - - ssize_t r; - while(len > 0) { - r = write(st->fd, data, len); - if (r < 1) return PARSER_ERR_SYSTEM; - st->stat.st_size += r; - - len -= r; - data += r; - } - - return PARSER_ERR_OK; -} - -parser_t PARSER_BINARY = { - "Raw BINARY", - binary_init, - binary_open, - binary_close, - binary_size, - binary_read, - binary_write -}; - diff --git a/linux/src/stm32flash_serial/src/parsers/binary.h b/linux/src/stm32flash_serial/src/parsers/binary.h deleted file mode 100644 index d989acfa0..000000000 --- a/linux/src/stm32flash_serial/src/parsers/binary.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _PARSER_BINARY_H -#define _PARSER_BINARY_H - -#include "parser.h" - -extern parser_t PARSER_BINARY; -#endif diff --git a/linux/src/stm32flash_serial/src/parsers/hex.c b/linux/src/stm32flash_serial/src/parsers/hex.c deleted file mode 100644 index 3baf85623..000000000 --- a/linux/src/stm32flash_serial/src/parsers/hex.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include - -#include "hex.h" -#include "../utils.h" - -typedef struct { - size_t data_len, offset; - uint8_t *data; - uint8_t base; -} hex_t; - -void* hex_init() { - return calloc(sizeof(hex_t), 1); -} - -parser_err_t hex_open(void *storage, const char *filename, const char write) { - hex_t *st = storage; - if (write) { - return PARSER_ERR_RDONLY; - } else { - char mark; - int i, fd; - uint8_t checksum; - unsigned int c; - uint32_t base = 0; - unsigned int last_address = 0x0; - - fd = open(filename, O_RDONLY); - if (fd < 0) - return PARSER_ERR_SYSTEM; - - /* read in the file */ - - while(read(fd, &mark, 1) != 0) { - if (mark == '\n' || mark == '\r') continue; - if (mark != ':') - return PARSER_ERR_INVALID_FILE; - - char buffer[9]; - unsigned int reclen, address, type; - uint8_t *record = NULL; - - /* get the reclen, address, and type */ - buffer[8] = 0; - if (read(fd, &buffer, 8) != 8) return PARSER_ERR_INVALID_FILE; - if (sscanf(buffer, "%2x%4x%2x", &reclen, &address, &type) != 3) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - /* setup the checksum */ - checksum = - reclen + - ((address & 0xFF00) >> 8) + - ((address & 0x00FF) >> 0) + - type; - - switch(type) { - /* data record */ - case 0: - c = address - last_address; - st->data = realloc(st->data, st->data_len + c + reclen); - - /* if there is a gap, set it to 0xff and increment the length */ - if (c > 0) { - memset(&st->data[st->data_len], 0xff, c); - st->data_len += c; - } - - last_address = address + reclen; - record = &st->data[st->data_len]; - st->data_len += reclen; - break; - - /* extended segment address record */ - case 2: - base = 0; - break; - - /* extended linear address record */ - case 4: - base = address; - break; - } - - buffer[2] = 0; - for(i = 0; i < reclen; ++i) { - if (read(fd, &buffer, 2) != 2 || sscanf(buffer, "%2x", &c) != 1) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - /* add the byte to the checksum */ - checksum += c; - - switch(type) { - case 0: - if (record != NULL) { - record[i] = c; - } else { - return PARSER_ERR_INVALID_FILE; - } - break; - - case 2: - case 4: - base = (base << 8) | c; - break; - } - } - - /* read, scan, and verify the checksum */ - if ( - read(fd, &buffer, 2 ) != 2 || - sscanf(buffer, "%2x", &c) != 1 || - (uint8_t)(checksum + c) != 0x00 - ) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - switch(type) { - /* EOF */ - case 1: - close(fd); - return PARSER_ERR_OK; - - /* address record */ - case 2: base = base << 4; - case 4: base = be_u32(base); - /* Reset last_address since our base changed */ - last_address = 0; - - if (st->base == 0) { - st->base = base; - break; - } - - /* we cant cope with files out of order */ - if (base < st->base) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - /* if there is a gap, enlarge and fill with zeros */ - unsigned int len = base - st->base; - if (len > st->data_len) { - st->data = realloc(st->data, len); - memset(&st->data[st->data_len], 0, len - st->data_len); - st->data_len = len; - } - break; - } - } - - close(fd); - return PARSER_ERR_OK; - } -} - -parser_err_t hex_close(void *storage) { - hex_t *st = storage; - if (st) free(st->data); - free(st); - return PARSER_ERR_OK; -} - -unsigned int hex_size(void *storage) { - hex_t *st = storage; - return st->data_len; -} - -parser_err_t hex_read(void *storage, void *data, unsigned int *len) { - hex_t *st = storage; - unsigned int left = st->data_len - st->offset; - unsigned int get = left > *len ? *len : left; - - memcpy(data, &st->data[st->offset], get); - st->offset += get; - - *len = get; - return PARSER_ERR_OK; -} - -parser_err_t hex_write(void *storage, void *data, unsigned int len) { - return PARSER_ERR_RDONLY; -} - -parser_t PARSER_HEX = { - "Intel HEX", - hex_init, - hex_open, - hex_close, - hex_size, - hex_read, - hex_write -}; - diff --git a/linux/src/stm32flash_serial/src/parsers/hex.h b/linux/src/stm32flash_serial/src/parsers/hex.h deleted file mode 100644 index 02413c9c9..000000000 --- a/linux/src/stm32flash_serial/src/parsers/hex.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _PARSER_HEX_H -#define _PARSER_HEX_H - -#include "parser.h" - -extern parser_t PARSER_HEX; -#endif diff --git a/linux/src/stm32flash_serial/src/parsers/parser.h b/linux/src/stm32flash_serial/src/parsers/parser.h deleted file mode 100644 index c2fae3cf8..000000000 --- a/linux/src/stm32flash_serial/src/parsers/parser.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _H_PARSER -#define _H_PARSER - -enum parser_err { - PARSER_ERR_OK, - PARSER_ERR_SYSTEM, - PARSER_ERR_INVALID_FILE, - PARSER_ERR_WRONLY, - PARSER_ERR_RDONLY -}; -typedef enum parser_err parser_err_t; - -struct parser { - const char *name; - void* (*init )(); /* initialise the parser */ - parser_err_t (*open )(void *storage, const char *filename, const char write); /* open the file for read|write */ - parser_err_t (*close)(void *storage); /* close and free the parser */ - unsigned int (*size )(void *storage); /* get the total data size */ - parser_err_t (*read )(void *storage, void *data, unsigned int *len); /* read a block of data */ - parser_err_t (*write)(void *storage, void *data, unsigned int len); /* write a block of data */ -}; -typedef struct parser parser_t; - -static inline const char* parser_errstr(parser_err_t err) { - switch(err) { - case PARSER_ERR_OK : return "OK"; - case PARSER_ERR_SYSTEM : return "System Error"; - case PARSER_ERR_INVALID_FILE: return "Invalid File"; - case PARSER_ERR_WRONLY : return "Parser can only write"; - case PARSER_ERR_RDONLY : return "Parser can only read"; - default: - return "Unknown Error"; - } -} - -#endif diff --git a/linux/src/stm32flash_serial/src/port.c b/linux/src/stm32flash_serial/src/port.c deleted file mode 100644 index 08e58cc34..000000000 --- a/linux/src/stm32flash_serial/src/port.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include - -#include "serial.h" -#include "port.h" - - -extern struct port_interface port_serial; -extern struct port_interface port_i2c; - -static struct port_interface *ports[] = { - &port_serial, - &port_i2c, - NULL, -}; - - -port_err_t port_open(struct port_options *ops, struct port_interface **outport) -{ - int ret; - static struct port_interface **port; - - for (port = ports; *port; port++) { - ret = (*port)->open(*port, ops); - if (ret == PORT_ERR_NODEV) - continue; - if (ret == PORT_ERR_OK) - break; - fprintf(stderr, "Error probing interface \"%s\"\n", - (*port)->name); - } - if (*port == NULL) { - fprintf(stderr, "Cannot handle device \"%s\"\n", - ops->device); - return PORT_ERR_UNKNOWN; - } - - *outport = *port; - return PORT_ERR_OK; -} diff --git a/linux/src/stm32flash_serial/src/port.h b/linux/src/stm32flash_serial/src/port.h deleted file mode 100644 index 290f03496..000000000 --- a/linux/src/stm32flash_serial/src/port.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _H_PORT -#define _H_PORT - -typedef enum { - PORT_ERR_OK = 0, - PORT_ERR_NODEV, /* No such device */ - PORT_ERR_TIMEDOUT, /* Operation timed out */ - PORT_ERR_UNKNOWN, -} port_err_t; - -/* flags */ -#define PORT_BYTE (1 << 0) /* byte (not frame) oriented */ -#define PORT_GVR_ETX (1 << 1) /* cmd GVR returns protection status */ -#define PORT_CMD_INIT (1 << 2) /* use INIT cmd to autodetect speed */ -#define PORT_RETRY (1 << 3) /* allowed read() retry after timeout */ -#define PORT_STRETCH_W (1 << 4) /* warning for no-stretching commands */ - -/* all options and flags used to open and configure an interface */ -struct port_options { - const char *device; - serial_baud_t baudRate; - const char *serial_mode; - int bus_addr; - int rx_frame_max; - int tx_frame_max; -}; - -/* - * Specify the length of reply for command GET - * This is helpful for frame-oriented protocols, e.g. i2c, to avoid time - * consuming try-fail-timeout-retry operation. - * On byte-oriented protocols, i.e. UART, this information would be skipped - * after read the first byte, so not needed. - */ -struct varlen_cmd { - uint8_t version; - uint8_t length; -}; - -struct port_interface { - const char *name; - unsigned flags; - port_err_t (*open)(struct port_interface *port, struct port_options *ops); - port_err_t (*close)(struct port_interface *port); - port_err_t (*read)(struct port_interface *port, void *buf, size_t nbyte); - port_err_t (*write)(struct port_interface *port, void *buf, size_t nbyte); - port_err_t (*gpio)(struct port_interface *port, serial_gpio_t n, int level); - const char *(*get_cfg_str)(struct port_interface *port); - struct varlen_cmd *cmd_get_reply; - void *private; -}; - -port_err_t port_open(struct port_options *ops, struct port_interface **outport); - -#endif diff --git a/linux/src/stm32flash_serial/src/protocol.txt b/linux/src/stm32flash_serial/src/protocol.txt deleted file mode 100644 index 039109908..000000000 --- a/linux/src/stm32flash_serial/src/protocol.txt +++ /dev/null @@ -1,19 +0,0 @@ -The communication protocol used by ST bootloader is documented in following ST -application notes, depending on communication port. - -In current version of stm32flash are supported only UART and I2C ports. - -* AN3154: CAN protocol used in the STM32 bootloader - http://www.st.com/web/en/resource/technical/document/application_note/CD00264321.pdf - -* AN3155: USART protocol used in the STM32(TM) bootloader - http://www.st.com/web/en/resource/technical/document/application_note/CD00264342.pdf - -* AN4221: I2C protocol used in the STM32 bootloader - http://www.st.com/web/en/resource/technical/document/application_note/DM00072315.pdf - -* AN4286: SPI protocol used in the STM32 bootloader - http://www.st.com/web/en/resource/technical/document/application_note/DM00081379.pdf - -Boot mode selection for STM32 is documented in ST application note AN2606, available in ST website: - http://www.st.com/web/en/resource/technical/document/application_note/CD00167594.pdf diff --git a/linux/src/stm32flash_serial/src/serial.h b/linux/src/stm32flash_serial/src/serial.h deleted file mode 100644 index 227ba163b..000000000 --- a/linux/src/stm32flash_serial/src/serial.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _SERIAL_H -#define _SERIAL_H - -typedef struct serial serial_t; - -typedef enum { - SERIAL_PARITY_NONE, - SERIAL_PARITY_EVEN, - SERIAL_PARITY_ODD, - - SERIAL_PARITY_INVALID -} serial_parity_t; - -typedef enum { - SERIAL_BITS_5, - SERIAL_BITS_6, - SERIAL_BITS_7, - SERIAL_BITS_8, - - SERIAL_BITS_INVALID -} serial_bits_t; - -typedef enum { - SERIAL_BAUD_1200, - SERIAL_BAUD_1800, - SERIAL_BAUD_2400, - SERIAL_BAUD_4800, - SERIAL_BAUD_9600, - SERIAL_BAUD_19200, - SERIAL_BAUD_38400, - SERIAL_BAUD_57600, - SERIAL_BAUD_115200, - SERIAL_BAUD_128000, - SERIAL_BAUD_230400, - SERIAL_BAUD_256000, - SERIAL_BAUD_460800, - SERIAL_BAUD_500000, - SERIAL_BAUD_576000, - SERIAL_BAUD_921600, - SERIAL_BAUD_1000000, - SERIAL_BAUD_1500000, - SERIAL_BAUD_2000000, - - SERIAL_BAUD_INVALID -} serial_baud_t; - -typedef enum { - SERIAL_STOPBIT_1, - SERIAL_STOPBIT_2, - - SERIAL_STOPBIT_INVALID -} serial_stopbit_t; - -typedef enum { - GPIO_RTS = 1, - GPIO_DTR, - GPIO_BRK, -} serial_gpio_t; - -/* common helper functions */ -serial_baud_t serial_get_baud(const unsigned int baud); -unsigned int serial_get_baud_int(const serial_baud_t baud); -serial_bits_t serial_get_bits(const char *mode); -unsigned int serial_get_bits_int(const serial_bits_t bits); -serial_parity_t serial_get_parity(const char *mode); -char serial_get_parity_str(const serial_parity_t parity); -serial_stopbit_t serial_get_stopbit(const char *mode); -unsigned int serial_get_stopbit_int(const serial_stopbit_t stopbit); - -#endif diff --git a/linux/src/stm32flash_serial/src/serial_common.c b/linux/src/stm32flash_serial/src/serial_common.c deleted file mode 100644 index 43e48e1ac..000000000 --- a/linux/src/stm32flash_serial/src/serial_common.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "serial.h" - -serial_baud_t serial_get_baud(const unsigned int baud) { - switch(baud) { - case 1200: return SERIAL_BAUD_1200 ; - case 1800: return SERIAL_BAUD_1800 ; - case 2400: return SERIAL_BAUD_2400 ; - case 4800: return SERIAL_BAUD_4800 ; - case 9600: return SERIAL_BAUD_9600 ; - case 19200: return SERIAL_BAUD_19200 ; - case 38400: return SERIAL_BAUD_38400 ; - case 57600: return SERIAL_BAUD_57600 ; - case 115200: return SERIAL_BAUD_115200; - case 128000: return SERIAL_BAUD_128000; - case 230400: return SERIAL_BAUD_230400; - case 256000: return SERIAL_BAUD_256000; - case 460800: return SERIAL_BAUD_460800; - case 500000: return SERIAL_BAUD_500000; - case 576000: return SERIAL_BAUD_576000; - case 921600: return SERIAL_BAUD_921600; - case 1000000: return SERIAL_BAUD_1000000; - case 1500000: return SERIAL_BAUD_1500000; - case 2000000: return SERIAL_BAUD_2000000; - - default: - return SERIAL_BAUD_INVALID; - } -} - -unsigned int serial_get_baud_int(const serial_baud_t baud) { - switch(baud) { - case SERIAL_BAUD_1200 : return 1200 ; - case SERIAL_BAUD_1800 : return 1800 ; - case SERIAL_BAUD_2400 : return 2400 ; - case SERIAL_BAUD_4800 : return 4800 ; - case SERIAL_BAUD_9600 : return 9600 ; - case SERIAL_BAUD_19200 : return 19200 ; - case SERIAL_BAUD_38400 : return 38400 ; - case SERIAL_BAUD_57600 : return 57600 ; - case SERIAL_BAUD_115200: return 115200; - case SERIAL_BAUD_128000: return 128000; - case SERIAL_BAUD_230400: return 230400; - case SERIAL_BAUD_256000: return 256000; - case SERIAL_BAUD_460800: return 460800; - case SERIAL_BAUD_500000: return 500000; - case SERIAL_BAUD_576000: return 576000; - case SERIAL_BAUD_921600: return 921600; - case SERIAL_BAUD_1000000: return 1000000; - case SERIAL_BAUD_1500000: return 1500000; - case SERIAL_BAUD_2000000: return 2000000; - - case SERIAL_BAUD_INVALID: - default: - return 0; - } -} - -serial_bits_t serial_get_bits(const char *mode) { - if (!mode) - return SERIAL_BITS_INVALID; - switch(mode[0]) { - case '5': return SERIAL_BITS_5; - case '6': return SERIAL_BITS_6; - case '7': return SERIAL_BITS_7; - case '8': return SERIAL_BITS_8; - - default: - return SERIAL_BITS_INVALID; - } -} - -unsigned int serial_get_bits_int(const serial_bits_t bits) { - switch(bits) { - case SERIAL_BITS_5: return 5; - case SERIAL_BITS_6: return 6; - case SERIAL_BITS_7: return 7; - case SERIAL_BITS_8: return 8; - - default: - return 0; - } -} - -serial_parity_t serial_get_parity(const char *mode) { - if (!mode || !mode[0]) - return SERIAL_PARITY_INVALID; - switch(mode[1]) { - case 'N': - case 'n': - return SERIAL_PARITY_NONE; - case 'E': - case 'e': - return SERIAL_PARITY_EVEN; - case 'O': - case 'o': - return SERIAL_PARITY_ODD; - - default: - return SERIAL_PARITY_INVALID; - } -} - -char serial_get_parity_str(const serial_parity_t parity) { - switch(parity) { - case SERIAL_PARITY_NONE: return 'N'; - case SERIAL_PARITY_EVEN: return 'E'; - case SERIAL_PARITY_ODD : return 'O'; - - default: - return ' '; - } -} - -serial_stopbit_t serial_get_stopbit(const char *mode) { - if (!mode || !mode[0] || !mode[1]) - return SERIAL_STOPBIT_INVALID; - switch(mode[2]) { - case '1': return SERIAL_STOPBIT_1; - case '2': return SERIAL_STOPBIT_2; - - default: - return SERIAL_STOPBIT_INVALID; - } -} - -unsigned int serial_get_stopbit_int(const serial_stopbit_t stopbit) { - switch(stopbit) { - case SERIAL_STOPBIT_1: return 1; - case SERIAL_STOPBIT_2: return 2; - - default: - return 0; - } -} - diff --git a/linux/src/stm32flash_serial/src/serial_platform.c b/linux/src/stm32flash_serial/src/serial_platform.c deleted file mode 100644 index 98e256921..000000000 --- a/linux/src/stm32flash_serial/src/serial_platform.c +++ /dev/null @@ -1,5 +0,0 @@ -#if defined(__WIN32__) || defined(__CYGWIN__) -# include "serial_w32.c" -#else -# include "serial_posix.c" -#endif diff --git a/linux/src/stm32flash_serial/src/serial_posix.c b/linux/src/stm32flash_serial/src/serial_posix.c deleted file mode 100644 index 284b35b20..000000000 --- a/linux/src/stm32flash_serial/src/serial_posix.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "serial.h" -#include "port.h" - -struct serial { - int fd; - struct termios oldtio; - struct termios newtio; - char setup_str[11]; -}; - -static serial_t *serial_open(const char *device) -{ - serial_t *h = calloc(sizeof(serial_t), 1); - - h->fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); - if (h->fd < 0) { - free(h); - return NULL; - } - fcntl(h->fd, F_SETFL, 0); - - tcgetattr(h->fd, &h->oldtio); - tcgetattr(h->fd, &h->newtio); - - return h; -} - -static void serial_flush(const serial_t *h) -{ - tcflush(h->fd, TCIFLUSH); -} - -static void serial_close(serial_t *h) -{ - serial_flush(h); - tcsetattr(h->fd, TCSANOW, &h->oldtio); - close(h->fd); - free(h); -} - -static port_err_t serial_setup(serial_t *h, const serial_baud_t baud, - const serial_bits_t bits, - const serial_parity_t parity, - const serial_stopbit_t stopbit) -{ - speed_t port_baud; - tcflag_t port_bits; - tcflag_t port_parity; - tcflag_t port_stop; - struct termios settings; - - switch (baud) { - case SERIAL_BAUD_1200: port_baud = B1200; break; - case SERIAL_BAUD_1800: port_baud = B1800; break; - case SERIAL_BAUD_2400: port_baud = B2400; break; - case SERIAL_BAUD_4800: port_baud = B4800; break; - case SERIAL_BAUD_9600: port_baud = B9600; break; - case SERIAL_BAUD_19200: port_baud = B19200; break; - case SERIAL_BAUD_38400: port_baud = B38400; break; - case SERIAL_BAUD_57600: port_baud = B57600; break; - case SERIAL_BAUD_115200: port_baud = B115200; break; - case SERIAL_BAUD_230400: port_baud = B230400; break; -#ifdef B460800 - case SERIAL_BAUD_460800: port_baud = B460800; break; -#endif /* B460800 */ -#ifdef B921600 - case SERIAL_BAUD_921600: port_baud = B921600; break; -#endif /* B921600 */ -#ifdef B500000 - case SERIAL_BAUD_500000: port_baud = B500000; break; -#endif /* B500000 */ -#ifdef B576000 - case SERIAL_BAUD_576000: port_baud = B576000; break; -#endif /* B576000 */ -#ifdef B1000000 - case SERIAL_BAUD_1000000: port_baud = B1000000; break; -#endif /* B1000000 */ -#ifdef B1500000 - case SERIAL_BAUD_1500000: port_baud = B1500000; break; -#endif /* B1500000 */ -#ifdef B2000000 - case SERIAL_BAUD_2000000: port_baud = B2000000; break; -#endif /* B2000000 */ - - case SERIAL_BAUD_INVALID: - default: - return PORT_ERR_UNKNOWN; - } - - switch (bits) { - case SERIAL_BITS_5: port_bits = CS5; break; - case SERIAL_BITS_6: port_bits = CS6; break; - case SERIAL_BITS_7: port_bits = CS7; break; - case SERIAL_BITS_8: port_bits = CS8; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (parity) { - case SERIAL_PARITY_NONE: port_parity = 0; break; - case SERIAL_PARITY_EVEN: port_parity = PARENB; break; - case SERIAL_PARITY_ODD: port_parity = PARENB | PARODD; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (stopbit) { - case SERIAL_STOPBIT_1: port_stop = 0; break; - case SERIAL_STOPBIT_2: port_stop = CSTOPB; break; - - default: - return PORT_ERR_UNKNOWN; - } - - /* reset the settings */ -#ifndef __sun /* Used by GNU and BSD. Ignore __SVR4 in test. */ - cfmakeraw(&h->newtio); -#else /* __sun */ - h->newtio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR - | IGNCR | ICRNL | IXON); - if (port_parity) - h->newtio.c_iflag |= INPCK; - - h->newtio.c_oflag &= ~OPOST; - h->newtio.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - h->newtio.c_cflag &= ~(CSIZE | PARENB); - h->newtio.c_cflag |= CS8; -#endif /* __sun */ -#ifdef __QNXNTO__ - h->newtio.c_cflag &= ~(CSIZE | IHFLOW | OHFLOW); -#else - h->newtio.c_cflag &= ~(CSIZE | CRTSCTS); -#endif - h->newtio.c_cflag &= ~(CSIZE | CRTSCTS); - h->newtio.c_iflag &= ~(IXON | IXOFF | IXANY | IGNPAR); - h->newtio.c_lflag &= ~(ECHOK | ECHOCTL | ECHOKE); - h->newtio.c_oflag &= ~(OPOST | ONLCR); - - /* setup the new settings */ - cfsetispeed(&h->newtio, port_baud); - cfsetospeed(&h->newtio, port_baud); - h->newtio.c_cflag |= - port_parity | - port_bits | - port_stop | - CLOCAL | - CREAD; - - h->newtio.c_cc[VMIN] = 0; - h->newtio.c_cc[VTIME] = 5; /* in units of 0.1 s */ - - /* set the settings */ - serial_flush(h); - if (tcsetattr(h->fd, TCSANOW, &h->newtio) != 0) - return PORT_ERR_UNKNOWN; - -/* this check fails on CDC-ACM devices, bits 16 and 17 of cflag differ! - * it has been disabled below for now -jcw, 2015-11-09 - if (settings.c_cflag != h->newtio.c_cflag) - fprintf(stderr, "c_cflag mismatch %lx\n", - settings.c_cflag ^ h->newtio.c_cflag); - */ - - /* confirm they were set */ - tcgetattr(h->fd, &settings); - if (settings.c_iflag != h->newtio.c_iflag || - settings.c_oflag != h->newtio.c_oflag || - //settings.c_cflag != h->newtio.c_cflag || - settings.c_lflag != h->newtio.c_lflag) - return PORT_ERR_UNKNOWN; - - snprintf(h->setup_str, sizeof(h->setup_str), "%u %d%c%d", - serial_get_baud_int(baud), - serial_get_bits_int(bits), - serial_get_parity_str(parity), - serial_get_stopbit_int(stopbit)); - return PORT_ERR_OK; -} - -/* - * Roger clark. - * This function is no longer used. But has just been commented out in case it needs - * to be reinstated in the future - -static int startswith(const char *haystack, const char *needle) { - return strncmp(haystack, needle, strlen(needle)) == 0; -} -*/ - -static int is_tty(const char *path) { - char resolved[PATH_MAX]; - - if(!realpath(path, resolved)) return 0; - - - /* - * Roger Clark - * Commented out this check, because on OSX some devices are /dev/cu - * and some users use symbolic links to devices, hence the name may not even start - * with /dev - - if(startswith(resolved, "/dev/tty")) return 1; - - return 0; - */ - - return 1; -} - -static port_err_t serial_posix_open(struct port_interface *port, - struct port_options *ops) -{ - serial_t *h; - - /* 1. check device name match */ - if (!is_tty(ops->device)) - return PORT_ERR_NODEV; - - /* 2. check options */ - if (ops->baudRate == SERIAL_BAUD_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_bits(ops->serial_mode) == SERIAL_BITS_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_parity(ops->serial_mode) == SERIAL_PARITY_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_stopbit(ops->serial_mode) == SERIAL_STOPBIT_INVALID) - return PORT_ERR_UNKNOWN; - - /* 3. open it */ - h = serial_open(ops->device); - if (h == NULL) - return PORT_ERR_UNKNOWN; - - /* 4. set options */ - if (serial_setup(h, ops->baudRate, - serial_get_bits(ops->serial_mode), - serial_get_parity(ops->serial_mode), - serial_get_stopbit(ops->serial_mode) - ) != PORT_ERR_OK) { - serial_close(h); - return PORT_ERR_UNKNOWN; - } - - port->private = h; - return PORT_ERR_OK; -} - -static port_err_t serial_posix_close(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - serial_close(h); - port->private = NULL; - return PORT_ERR_OK; -} - -static port_err_t serial_posix_read(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - ssize_t r; - uint8_t *pos = (uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - r = read(h->fd, pos, nbyte); - if (r == 0) - return PORT_ERR_TIMEDOUT; - if (r < 0) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_posix_write(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - ssize_t r; - const uint8_t *pos = (const uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - r = write(h->fd, pos, nbyte); - if (r < 1) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_posix_gpio(struct port_interface *port, - serial_gpio_t n, int level) -{ - serial_t *h; - int bit, lines; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - switch (n) { - case GPIO_RTS: - bit = TIOCM_RTS; - break; - - case GPIO_DTR: - bit = TIOCM_DTR; - break; - - case GPIO_BRK: - if (level == 0) - return PORT_ERR_OK; - if (tcsendbreak(h->fd, 1)) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; - - default: - return PORT_ERR_UNKNOWN; - } - - /* handle RTS/DTR */ - if (ioctl(h->fd, TIOCMGET, &lines)) - return PORT_ERR_UNKNOWN; - lines = level ? lines | bit : lines & ~bit; - if (ioctl(h->fd, TIOCMSET, &lines)) - return PORT_ERR_UNKNOWN; - - return PORT_ERR_OK; -} - -static const char *serial_posix_get_cfg_str(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - return h ? h->setup_str : "INVALID"; -} - -struct port_interface port_serial = { - .name = "serial_posix", - .flags = PORT_BYTE | PORT_GVR_ETX | PORT_CMD_INIT | PORT_RETRY, - .open = serial_posix_open, - .close = serial_posix_close, - .read = serial_posix_read, - .write = serial_posix_write, - .gpio = serial_posix_gpio, - .get_cfg_str = serial_posix_get_cfg_str, -}; diff --git a/linux/src/stm32flash_serial/src/serial_w32.c b/linux/src/stm32flash_serial/src/serial_w32.c deleted file mode 100644 index 56772c0a0..000000000 --- a/linux/src/stm32flash_serial/src/serial_w32.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2010 Gareth McMullin - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "serial.h" -#include "port.h" - -struct serial { - HANDLE fd; - DCB oldtio; - DCB newtio; - char setup_str[11]; -}; - -static serial_t *serial_open(const char *device) -{ - serial_t *h = calloc(sizeof(serial_t), 1); - char *devName; - - /* timeout in ms */ - COMMTIMEOUTS timeouts = {MAXDWORD, MAXDWORD, 500, 0, 0}; - - /* Fix the device name if required */ - if (strlen(device) > 4 && device[0] != '\\') { - devName = calloc(1, strlen(device) + 5); - sprintf(devName, "\\\\.\\%s", device); - } else { - devName = (char *)device; - } - - /* Create file handle for port */ - h->fd = CreateFile(devName, GENERIC_READ | GENERIC_WRITE, - 0, /* Exclusive access */ - NULL, /* No security */ - OPEN_EXISTING, - 0, /* No overlap */ - NULL); - - if (devName != device) - free(devName); - - if (h->fd == INVALID_HANDLE_VALUE) { - if (GetLastError() == ERROR_FILE_NOT_FOUND) - fprintf(stderr, "File not found: %s\n", device); - return NULL; - } - - SetupComm(h->fd, 4096, 4096); /* Set input and output buffer size */ - - SetCommTimeouts(h->fd, &timeouts); - - SetCommMask(h->fd, EV_ERR); /* Notify us of error events */ - - GetCommState(h->fd, &h->oldtio); /* Retrieve port parameters */ - GetCommState(h->fd, &h->newtio); /* Retrieve port parameters */ - - /* PurgeComm(h->fd, PURGE_RXABORT | PURGE_TXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); */ - - return h; -} - -static void serial_flush(const serial_t *h) -{ - /* We shouldn't need to flush in non-overlapping (blocking) mode */ - /* tcflush(h->fd, TCIFLUSH); */ -} - -static void serial_close(serial_t *h) -{ - serial_flush(h); - SetCommState(h->fd, &h->oldtio); - CloseHandle(h->fd); - free(h); -} - -static port_err_t serial_setup(serial_t *h, - const serial_baud_t baud, - const serial_bits_t bits, - const serial_parity_t parity, - const serial_stopbit_t stopbit) -{ - switch (baud) { - case SERIAL_BAUD_1200: h->newtio.BaudRate = CBR_1200; break; - /* case SERIAL_BAUD_1800: h->newtio.BaudRate = CBR_1800; break; */ - case SERIAL_BAUD_2400: h->newtio.BaudRate = CBR_2400; break; - case SERIAL_BAUD_4800: h->newtio.BaudRate = CBR_4800; break; - case SERIAL_BAUD_9600: h->newtio.BaudRate = CBR_9600; break; - case SERIAL_BAUD_19200: h->newtio.BaudRate = CBR_19200; break; - case SERIAL_BAUD_38400: h->newtio.BaudRate = CBR_38400; break; - case SERIAL_BAUD_57600: h->newtio.BaudRate = CBR_57600; break; - case SERIAL_BAUD_115200: h->newtio.BaudRate = CBR_115200; break; - case SERIAL_BAUD_128000: h->newtio.BaudRate = CBR_128000; break; - case SERIAL_BAUD_256000: h->newtio.BaudRate = CBR_256000; break; - /* These are not defined in WinBase.h and might work or not */ - case SERIAL_BAUD_230400: h->newtio.BaudRate = 230400; break; - case SERIAL_BAUD_460800: h->newtio.BaudRate = 460800; break; - case SERIAL_BAUD_500000: h->newtio.BaudRate = 500000; break; - case SERIAL_BAUD_576000: h->newtio.BaudRate = 576000; break; - case SERIAL_BAUD_921600: h->newtio.BaudRate = 921600; break; - case SERIAL_BAUD_1000000: h->newtio.BaudRate = 1000000; break; - case SERIAL_BAUD_1500000: h->newtio.BaudRate = 1500000; break; - case SERIAL_BAUD_2000000: h->newtio.BaudRate = 2000000; break; - case SERIAL_BAUD_INVALID: - - default: - return PORT_ERR_UNKNOWN; - } - - switch (bits) { - case SERIAL_BITS_5: h->newtio.ByteSize = 5; break; - case SERIAL_BITS_6: h->newtio.ByteSize = 6; break; - case SERIAL_BITS_7: h->newtio.ByteSize = 7; break; - case SERIAL_BITS_8: h->newtio.ByteSize = 8; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (parity) { - case SERIAL_PARITY_NONE: h->newtio.Parity = NOPARITY; break; - case SERIAL_PARITY_EVEN: h->newtio.Parity = EVENPARITY; break; - case SERIAL_PARITY_ODD: h->newtio.Parity = ODDPARITY; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (stopbit) { - case SERIAL_STOPBIT_1: h->newtio.StopBits = ONESTOPBIT; break; - case SERIAL_STOPBIT_2: h->newtio.StopBits = TWOSTOPBITS; break; - - default: - return PORT_ERR_UNKNOWN; - } - - /* reset the settings */ - h->newtio.fOutxCtsFlow = FALSE; - h->newtio.fOutxDsrFlow = FALSE; - h->newtio.fOutX = FALSE; - h->newtio.fInX = FALSE; - h->newtio.fNull = 0; - h->newtio.fAbortOnError = 0; - - /* set the settings */ - serial_flush(h); - if (!SetCommState(h->fd, &h->newtio)) - return PORT_ERR_UNKNOWN; - - snprintf(h->setup_str, sizeof(h->setup_str), "%u %d%c%d", - serial_get_baud_int(baud), - serial_get_bits_int(bits), - serial_get_parity_str(parity), - serial_get_stopbit_int(stopbit) - ); - return PORT_ERR_OK; -} - -static port_err_t serial_w32_open(struct port_interface *port, - struct port_options *ops) -{ - serial_t *h; - - /* 1. check device name match */ - if (!((strlen(ops->device) == 4 || strlen(ops->device) == 5) - && !strncmp(ops->device, "COM", 3) && isdigit(ops->device[3])) - && !(!strncmp(ops->device, "\\\\.\\COM", strlen("\\\\.\\COM")) - && isdigit(ops->device[strlen("\\\\.\\COM")]))) - return PORT_ERR_NODEV; - - /* 2. check options */ - if (ops->baudRate == SERIAL_BAUD_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_bits(ops->serial_mode) == SERIAL_BITS_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_parity(ops->serial_mode) == SERIAL_PARITY_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_stopbit(ops->serial_mode) == SERIAL_STOPBIT_INVALID) - return PORT_ERR_UNKNOWN; - - /* 3. open it */ - h = serial_open(ops->device); - if (h == NULL) - return PORT_ERR_UNKNOWN; - - /* 4. set options */ - if (serial_setup(h, ops->baudRate, - serial_get_bits(ops->serial_mode), - serial_get_parity(ops->serial_mode), - serial_get_stopbit(ops->serial_mode) - ) != PORT_ERR_OK) { - serial_close(h); - return PORT_ERR_UNKNOWN; - } - - port->private = h; - return PORT_ERR_OK; -} - -static port_err_t serial_w32_close(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - serial_close(h); - port->private = NULL; - return PORT_ERR_OK; -} - -static port_err_t serial_w32_read(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - DWORD r; - uint8_t *pos = (uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - ReadFile(h->fd, pos, nbyte, &r, NULL); - if (r == 0) - return PORT_ERR_TIMEDOUT; - if (r < 0) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_w32_write(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - DWORD r; - uint8_t *pos = (uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - if (!WriteFile(h->fd, pos, nbyte, &r, NULL)) - return PORT_ERR_UNKNOWN; - if (r < 1) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_w32_gpio(struct port_interface *port, - serial_gpio_t n, int level) -{ - serial_t *h; - int bit; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - switch (n) { - case GPIO_RTS: - bit = level ? SETRTS : CLRRTS; - break; - - case GPIO_DTR: - bit = level ? SETDTR : CLRDTR; - break; - - case GPIO_BRK: - if (level == 0) - return PORT_ERR_OK; - if (EscapeCommFunction(h->fd, SETBREAK) == 0) - return PORT_ERR_UNKNOWN; - usleep(500000); - if (EscapeCommFunction(h->fd, CLRBREAK) == 0) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; - - default: - return PORT_ERR_UNKNOWN; - } - - /* handle RTS/DTR */ - if (EscapeCommFunction(h->fd, bit) == 0) - return PORT_ERR_UNKNOWN; - - return PORT_ERR_OK; -} - -static const char *serial_w32_get_cfg_str(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - return h ? h->setup_str : "INVALID"; -} - -struct port_interface port_serial = { - .name = "serial_w32", - .flags = PORT_BYTE | PORT_GVR_ETX | PORT_CMD_INIT | PORT_RETRY, - .open = serial_w32_open, - .close = serial_w32_close, - .read = serial_w32_read, - .write = serial_w32_write, - .gpio = serial_w32_gpio, - .get_cfg_str = serial_w32_get_cfg_str, -}; diff --git a/linux/src/stm32flash_serial/src/stm32.c b/linux/src/stm32flash_serial/src/stm32.c deleted file mode 100644 index 74047d244..000000000 --- a/linux/src/stm32flash_serial/src/stm32.c +++ /dev/null @@ -1,1048 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright 2010 Geoffrey McRae - Copyright 2012-2014 Tormod Volden - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include - -#include "stm32.h" -#include "port.h" -#include "utils.h" - -#define STM32_ACK 0x79 -#define STM32_NACK 0x1F -#define STM32_BUSY 0x76 - -#define STM32_CMD_INIT 0x7F -#define STM32_CMD_GET 0x00 /* get the version and command supported */ -#define STM32_CMD_GVR 0x01 /* get version and read protection status */ -#define STM32_CMD_GID 0x02 /* get ID */ -#define STM32_CMD_RM 0x11 /* read memory */ -#define STM32_CMD_GO 0x21 /* go */ -#define STM32_CMD_WM 0x31 /* write memory */ -#define STM32_CMD_WM_NS 0x32 /* no-stretch write memory */ -#define STM32_CMD_ER 0x43 /* erase */ -#define STM32_CMD_EE 0x44 /* extended erase */ -#define STM32_CMD_EE_NS 0x45 /* extended erase no-stretch */ -#define STM32_CMD_WP 0x63 /* write protect */ -#define STM32_CMD_WP_NS 0x64 /* write protect no-stretch */ -#define STM32_CMD_UW 0x73 /* write unprotect */ -#define STM32_CMD_UW_NS 0x74 /* write unprotect no-stretch */ -#define STM32_CMD_RP 0x82 /* readout protect */ -#define STM32_CMD_RP_NS 0x83 /* readout protect no-stretch */ -#define STM32_CMD_UR 0x92 /* readout unprotect */ -#define STM32_CMD_UR_NS 0x93 /* readout unprotect no-stretch */ -#define STM32_CMD_CRC 0xA1 /* compute CRC */ -#define STM32_CMD_ERR 0xFF /* not a valid command */ - -#define STM32_RESYNC_TIMEOUT 35 /* seconds */ -#define STM32_MASSERASE_TIMEOUT 35 /* seconds */ -#define STM32_SECTERASE_TIMEOUT 5 /* seconds */ -#define STM32_BLKWRITE_TIMEOUT 1 /* seconds */ -#define STM32_WUNPROT_TIMEOUT 1 /* seconds */ -#define STM32_WPROT_TIMEOUT 1 /* seconds */ -#define STM32_RPROT_TIMEOUT 1 /* seconds */ - -#define STM32_CMD_GET_LENGTH 17 /* bytes in the reply */ - -struct stm32_cmd { - uint8_t get; - uint8_t gvr; - uint8_t gid; - uint8_t rm; - uint8_t go; - uint8_t wm; - uint8_t er; /* this may be extended erase */ - uint8_t wp; - uint8_t uw; - uint8_t rp; - uint8_t ur; - uint8_t crc; -}; - -/* Reset code for ARMv7-M (Cortex-M3) and ARMv6-M (Cortex-M0) - * see ARMv7-M or ARMv6-M Architecture Reference Manual (table B3-8) - * or "The definitive guide to the ARM Cortex-M3", section 14.4. - */ -static const uint8_t stm_reset_code[] = { - 0x01, 0x49, // ldr r1, [pc, #4] ; () - 0x02, 0x4A, // ldr r2, [pc, #8] ; () - 0x0A, 0x60, // str r2, [r1, #0] - 0xfe, 0xe7, // endless: b endless - 0x0c, 0xed, 0x00, 0xe0, // .word 0xe000ed0c = NVIC AIRCR register address - 0x04, 0x00, 0xfa, 0x05 // .word 0x05fa0004 = VECTKEY | SYSRESETREQ -}; - -static const uint32_t stm_reset_code_length = sizeof(stm_reset_code); - -extern const stm32_dev_t devices[]; - -static void stm32_warn_stretching(const char *f) -{ - fprintf(stderr, "Attention !!!\n"); - fprintf(stderr, "\tThis %s error could be caused by your I2C\n", f); - fprintf(stderr, "\tcontroller not accepting \"clock stretching\"\n"); - fprintf(stderr, "\tas required by bootloader.\n"); - fprintf(stderr, "\tCheck \"I2C.txt\" in stm32flash source code.\n"); -} - -static stm32_err_t stm32_get_ack_timeout(const stm32_t *stm, time_t timeout) -{ - struct port_interface *port = stm->port; - uint8_t byte; - port_err_t p_err; - time_t t0, t1; - - if (!(port->flags & PORT_RETRY)) - timeout = 0; - - if (timeout) - time(&t0); - - do { - p_err = port->read(port, &byte, 1); - if (p_err == PORT_ERR_TIMEDOUT && timeout) { - time(&t1); - if (t1 < t0 + timeout) - continue; - } - - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to read ACK byte\n"); - return STM32_ERR_UNKNOWN; - } - - if (byte == STM32_ACK) - return STM32_ERR_OK; - if (byte == STM32_NACK) - return STM32_ERR_NACK; - if (byte != STM32_BUSY) { - fprintf(stderr, "Got byte 0x%02x instead of ACK\n", - byte); - return STM32_ERR_UNKNOWN; - } - } while (1); -} - -static stm32_err_t stm32_get_ack(const stm32_t *stm) -{ - return stm32_get_ack_timeout(stm, 0); -} - -static stm32_err_t stm32_send_command_timeout(const stm32_t *stm, - const uint8_t cmd, - time_t timeout) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - port_err_t p_err; - uint8_t buf[2]; - - buf[0] = cmd; - buf[1] = cmd ^ 0xFF; - p_err = port->write(port, buf, 2); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to send command\n"); - return STM32_ERR_UNKNOWN; - } - s_err = stm32_get_ack_timeout(stm, timeout); - if (s_err == STM32_ERR_OK) - return STM32_ERR_OK; - if (s_err == STM32_ERR_NACK) - fprintf(stderr, "Got NACK from device on command 0x%02x\n", cmd); - else - fprintf(stderr, "Unexpected reply from device on command 0x%02x\n", cmd); - return STM32_ERR_UNKNOWN; -} - -static stm32_err_t stm32_send_command(const stm32_t *stm, const uint8_t cmd) -{ - return stm32_send_command_timeout(stm, cmd, 0); -} - -/* if we have lost sync, send a wrong command and expect a NACK */ -static stm32_err_t stm32_resync(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - port_err_t p_err; - uint8_t buf[2], ack; - time_t t0, t1; - - time(&t0); - t1 = t0; - - buf[0] = STM32_CMD_ERR; - buf[1] = STM32_CMD_ERR ^ 0xFF; - while (t1 < t0 + STM32_RESYNC_TIMEOUT) { - p_err = port->write(port, buf, 2); - if (p_err != PORT_ERR_OK) { - usleep(500000); - time(&t1); - continue; - } - p_err = port->read(port, &ack, 1); - if (p_err != PORT_ERR_OK) { - time(&t1); - continue; - } - if (ack == STM32_NACK) - return STM32_ERR_OK; - time(&t1); - } - return STM32_ERR_UNKNOWN; -} - -/* - * some command receive reply frame with variable length, and length is - * embedded in reply frame itself. - * We can guess the length, but if we guess wrong the protocol gets out - * of sync. - * Use resync for frame oriented interfaces (e.g. I2C) and byte-by-byte - * read for byte oriented interfaces (e.g. UART). - * - * to run safely, data buffer should be allocated for 256+1 bytes - * - * len is value of the first byte in the frame. - */ -static stm32_err_t stm32_guess_len_cmd(const stm32_t *stm, uint8_t cmd, - uint8_t *data, unsigned int len) -{ - struct port_interface *port = stm->port; - port_err_t p_err; - - if (stm32_send_command(stm, cmd) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - if (port->flags & PORT_BYTE) { - /* interface is UART-like */ - p_err = port->read(port, data, 1); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - len = data[0]; - p_err = port->read(port, data + 1, len + 1); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - return STM32_ERR_OK; - } - - p_err = port->read(port, data, len + 2); - if (p_err == PORT_ERR_OK && len == data[0]) - return STM32_ERR_OK; - if (p_err != PORT_ERR_OK) { - /* restart with only one byte */ - if (stm32_resync(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - if (stm32_send_command(stm, cmd) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - p_err = port->read(port, data, 1); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - } - - fprintf(stderr, "Re sync (len = %d)\n", data[0]); - if (stm32_resync(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - len = data[0]; - if (stm32_send_command(stm, cmd) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - p_err = port->read(port, data, len + 2); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - return STM32_ERR_OK; -} - -/* - * Some interface, e.g. UART, requires a specific init sequence to let STM32 - * autodetect the interface speed. - * The sequence is only required one time after reset. - * stm32flash has command line flag "-c" to prevent sending the init sequence - * in case it was already sent before. - * User can easily forget adding "-c". In this case the bootloader would - * interpret the init sequence as part of a command message, then waiting for - * the rest of the message blocking the interface. - * This function sends the init sequence and, in case of timeout, recovers - * the interface. - */ -static stm32_err_t stm32_send_init_seq(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - port_err_t p_err; - uint8_t byte, cmd = STM32_CMD_INIT; - - p_err = port->write(port, &cmd, 1); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to send init to device\n"); - return STM32_ERR_UNKNOWN; - } - p_err = port->read(port, &byte, 1); - if (p_err == PORT_ERR_OK && byte == STM32_ACK) - return STM32_ERR_OK; - if (p_err == PORT_ERR_OK && byte == STM32_NACK) { - /* We could get error later, but let's continue, for now. */ - fprintf(stderr, - "Warning: the interface was not closed properly.\n"); - return STM32_ERR_OK; - } - if (p_err != PORT_ERR_TIMEDOUT) { - fprintf(stderr, "Failed to init device.\n"); - return STM32_ERR_UNKNOWN; - } - - /* - * Check if previous STM32_CMD_INIT was taken as first byte - * of a command. Send a new byte, we should get back a NACK. - */ - p_err = port->write(port, &cmd, 1); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to send init to device\n"); - return STM32_ERR_UNKNOWN; - } - p_err = port->read(port, &byte, 1); - if (p_err == PORT_ERR_OK && byte == STM32_NACK) - return STM32_ERR_OK; - fprintf(stderr, "Failed to init device.\n"); - return STM32_ERR_UNKNOWN; -} - -/* find newer command by higher code */ -#define newer(prev, a) (((prev) == STM32_CMD_ERR) \ - ? (a) \ - : (((prev) > (a)) ? (prev) : (a))) - -stm32_t *stm32_init(struct port_interface *port, const char init) -{ - uint8_t len, val, buf[257]; - stm32_t *stm; - int i, new_cmds; - - stm = calloc(sizeof(stm32_t), 1); - stm->cmd = malloc(sizeof(stm32_cmd_t)); - memset(stm->cmd, STM32_CMD_ERR, sizeof(stm32_cmd_t)); - stm->port = port; - - if ((port->flags & PORT_CMD_INIT) && init) - if (stm32_send_init_seq(stm) != STM32_ERR_OK) - return NULL; - - /* get the version and read protection status */ - if (stm32_send_command(stm, STM32_CMD_GVR) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - /* From AN, only UART bootloader returns 3 bytes */ - len = (port->flags & PORT_GVR_ETX) ? 3 : 1; - if (port->read(port, buf, len) != PORT_ERR_OK) - return NULL; - stm->version = buf[0]; - stm->option1 = (port->flags & PORT_GVR_ETX) ? buf[1] : 0; - stm->option2 = (port->flags & PORT_GVR_ETX) ? buf[2] : 0; - if (stm32_get_ack(stm) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - /* get the bootloader information */ - len = STM32_CMD_GET_LENGTH; - if (port->cmd_get_reply) - for (i = 0; port->cmd_get_reply[i].length; i++) - if (stm->version == port->cmd_get_reply[i].version) { - len = port->cmd_get_reply[i].length; - break; - } - if (stm32_guess_len_cmd(stm, STM32_CMD_GET, buf, len) != STM32_ERR_OK) - return NULL; - len = buf[0] + 1; - stm->bl_version = buf[1]; - new_cmds = 0; - for (i = 1; i < len; i++) { - val = buf[i + 1]; - switch (val) { - case STM32_CMD_GET: - stm->cmd->get = val; break; - case STM32_CMD_GVR: - stm->cmd->gvr = val; break; - case STM32_CMD_GID: - stm->cmd->gid = val; break; - case STM32_CMD_RM: - stm->cmd->rm = val; break; - case STM32_CMD_GO: - stm->cmd->go = val; break; - case STM32_CMD_WM: - case STM32_CMD_WM_NS: - stm->cmd->wm = newer(stm->cmd->wm, val); - break; - case STM32_CMD_ER: - case STM32_CMD_EE: - case STM32_CMD_EE_NS: - stm->cmd->er = newer(stm->cmd->er, val); - break; - case STM32_CMD_WP: - case STM32_CMD_WP_NS: - stm->cmd->wp = newer(stm->cmd->wp, val); - break; - case STM32_CMD_UW: - case STM32_CMD_UW_NS: - stm->cmd->uw = newer(stm->cmd->uw, val); - break; - case STM32_CMD_RP: - case STM32_CMD_RP_NS: - stm->cmd->rp = newer(stm->cmd->rp, val); - break; - case STM32_CMD_UR: - case STM32_CMD_UR_NS: - stm->cmd->ur = newer(stm->cmd->ur, val); - break; - case STM32_CMD_CRC: - stm->cmd->crc = newer(stm->cmd->crc, val); - break; - default: - if (new_cmds++ == 0) - fprintf(stderr, - "GET returns unknown commands (0x%2x", - val); - else - fprintf(stderr, ", 0x%2x", val); - } - } - if (new_cmds) - fprintf(stderr, ")\n"); - if (stm32_get_ack(stm) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - if (stm->cmd->get == STM32_CMD_ERR - || stm->cmd->gvr == STM32_CMD_ERR - || stm->cmd->gid == STM32_CMD_ERR) { - fprintf(stderr, "Error: bootloader did not returned correct information from GET command\n"); - return NULL; - } - - /* get the device ID */ - if (stm32_guess_len_cmd(stm, stm->cmd->gid, buf, 1) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - len = buf[0] + 1; - if (len < 2) { - stm32_close(stm); - fprintf(stderr, "Only %d bytes sent in the PID, unknown/unsupported device\n", len); - return NULL; - } - stm->pid = (buf[1] << 8) | buf[2]; - if (len > 2) { - fprintf(stderr, "This bootloader returns %d extra bytes in PID:", len); - for (i = 2; i <= len ; i++) - fprintf(stderr, " %02x", buf[i]); - fprintf(stderr, "\n"); - } - if (stm32_get_ack(stm) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - stm->dev = devices; - while (stm->dev->id != 0x00 && stm->dev->id != stm->pid) - ++stm->dev; - - if (!stm->dev->id) { - fprintf(stderr, "Unknown/unsupported device (Device ID: 0x%03x)\n", stm->pid); - stm32_close(stm); - return NULL; - } - - return stm; -} - -void stm32_close(stm32_t *stm) -{ - if (stm) - free(stm->cmd); - free(stm); -} - -stm32_err_t stm32_read_memory(const stm32_t *stm, uint32_t address, - uint8_t data[], unsigned int len) -{ - struct port_interface *port = stm->port; - uint8_t buf[5]; - - if (!len) - return STM32_ERR_OK; - - if (len > 256) { - fprintf(stderr, "Error: READ length limit at 256 bytes\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->rm == STM32_CMD_ERR) { - fprintf(stderr, "Error: READ command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->rm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_send_command(stm, len - 1) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (port->read(port, data, len) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - return STM32_ERR_OK; -} - -stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address, - const uint8_t data[], unsigned int len) -{ - struct port_interface *port = stm->port; - uint8_t cs, buf[256 + 2]; - unsigned int i, aligned_len; - stm32_err_t s_err; - - if (!len) - return STM32_ERR_OK; - - if (len > 256) { - fprintf(stderr, "Error: READ length limit at 256 bytes\n"); - return STM32_ERR_UNKNOWN; - } - - /* must be 32bit aligned */ - if (address & 0x3 || len & 0x3) { - fprintf(stderr, "Error: WRITE address and length must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->wm == STM32_CMD_ERR) { - fprintf(stderr, "Error: WRITE command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - /* send the address and checksum */ - if (stm32_send_command(stm, stm->cmd->wm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - aligned_len = (len + 3) & ~3; - cs = aligned_len - 1; - buf[0] = aligned_len - 1; - for (i = 0; i < len; i++) { - cs ^= data[i]; - buf[i + 1] = data[i]; - } - /* padding data */ - for (i = len; i < aligned_len; i++) { - cs ^= 0xFF; - buf[i + 1] = 0xFF; - } - buf[aligned_len + 1] = cs; - if (port->write(port, buf, aligned_len + 2) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_BLKWRITE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->wm != STM32_CMD_WM_NS) - stm32_warn_stretching("write"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_wunprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->uw == STM32_CMD_ERR) { - fprintf(stderr, "Error: WRITE UNPROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->uw) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_WUNPROT_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to WRITE UNPROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->uw != STM32_CMD_UW_NS) - stm32_warn_stretching("WRITE UNPROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_wprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->wp == STM32_CMD_ERR) { - fprintf(stderr, "Error: WRITE PROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->wp) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_WPROT_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to WRITE PROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->wp != STM32_CMD_WP_NS) - stm32_warn_stretching("WRITE PROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_runprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->ur == STM32_CMD_ERR) { - fprintf(stderr, "Error: READOUT UNPROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->ur) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to READOUT UNPROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->ur != STM32_CMD_UR_NS) - stm32_warn_stretching("READOUT UNPROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_readprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->rp == STM32_CMD_ERR) { - fprintf(stderr, "Error: READOUT PROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->rp) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_RPROT_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to READOUT PROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->rp != STM32_CMD_RP_NS) - stm32_warn_stretching("READOUT PROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, uint8_t pages) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - port_err_t p_err; - - if (!pages) - return STM32_ERR_OK; - - if (stm->cmd->er == STM32_CMD_ERR) { - fprintf(stderr, "Error: ERASE command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->er) != STM32_ERR_OK) { - fprintf(stderr, "Can't initiate chip erase!\n"); - return STM32_ERR_UNKNOWN; - } - - /* The erase command reported by the bootloader is either 0x43, 0x44 or 0x45 */ - /* 0x44 is Extended Erase, a 2 byte based protocol and needs to be handled differently. */ - /* 0x45 is clock no-stretching version of Extended Erase for I2C port. */ - if (stm->cmd->er != STM32_CMD_ER) { - /* Not all chips using Extended Erase support mass erase */ - /* Currently known as not supporting mass erase is the Ultra Low Power STM32L15xx range */ - /* So if someone has not overridden the default, but uses one of these chips, take it out of */ - /* mass erase mode, so it will be done page by page. This maximum might not be correct either! */ - if (stm->pid == 0x416 && pages == 0xFF) - pages = 0xF8; /* works for the STM32L152RB with 128Kb flash */ - - if (pages == 0xFF) { - uint8_t buf[3]; - - /* 0xFFFF the magic number for mass erase */ - buf[0] = 0xFF; - buf[1] = 0xFF; - buf[2] = 0x00; /* checksum */ - if (port->write(port, buf, 3) != PORT_ERR_OK) { - fprintf(stderr, "Mass erase error.\n"); - return STM32_ERR_UNKNOWN; - } - s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Mass erase failed. Try specifying the number of pages to be erased.\n"); - if (port->flags & PORT_STRETCH_W - && stm->cmd->er != STM32_CMD_EE_NS) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; - } - - uint16_t pg_num; - uint8_t pg_byte; - uint8_t cs = 0; - uint8_t *buf; - int i = 0; - - buf = malloc(2 + 2 * pages + 1); - if (!buf) - return STM32_ERR_UNKNOWN; - - /* Number of pages to be erased - 1, two bytes, MSB first */ - pg_byte = (pages - 1) >> 8; - buf[i++] = pg_byte; - cs ^= pg_byte; - pg_byte = (pages - 1) & 0xFF; - buf[i++] = pg_byte; - cs ^= pg_byte; - - for (pg_num = spage; pg_num < spage + pages; pg_num++) { - pg_byte = pg_num >> 8; - cs ^= pg_byte; - buf[i++] = pg_byte; - pg_byte = pg_num & 0xFF; - cs ^= pg_byte; - buf[i++] = pg_byte; - } - buf[i++] = cs; - p_err = port->write(port, buf, i); - free(buf); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Page-by-page erase error.\n"); - return STM32_ERR_UNKNOWN; - } - - s_err = stm32_get_ack_timeout(stm, pages * STM32_SECTERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Page-by-page erase failed. Check the maximum pages your device supports.\n"); - if (port->flags & PORT_STRETCH_W - && stm->cmd->er != STM32_CMD_EE_NS) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - - return STM32_ERR_OK; - } - - /* And now the regular erase (0x43) for all other chips */ - if (pages == 0xFF) { - s_err = stm32_send_command_timeout(stm, 0xFF, STM32_MASSERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; - } else { - uint8_t cs = 0; - uint8_t pg_num; - uint8_t *buf; - int i = 0; - - buf = malloc(1 + pages + 1); - if (!buf) - return STM32_ERR_UNKNOWN; - - buf[i++] = pages - 1; - cs ^= (pages-1); - for (pg_num = spage; pg_num < (pages + spage); pg_num++) { - buf[i++] = pg_num; - cs ^= pg_num; - } - buf[i++] = cs; - p_err = port->write(port, buf, i); - free(buf); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Erase failed.\n"); - return STM32_ERR_UNKNOWN; - } - s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; - } -} - -static stm32_err_t stm32_run_raw_code(const stm32_t *stm, - uint32_t target_address, - const uint8_t *code, uint32_t code_size) -{ - uint32_t stack_le = le_u32(0x20002000); - uint32_t code_address_le = le_u32(target_address + 8); - uint32_t length = code_size + 8; - uint8_t *mem, *pos; - uint32_t address, w; - - /* Must be 32-bit aligned */ - if (target_address & 0x3) { - fprintf(stderr, "Error: code address must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - mem = malloc(length); - if (!mem) - return STM32_ERR_UNKNOWN; - - memcpy(mem, &stack_le, sizeof(uint32_t)); - memcpy(mem + 4, &code_address_le, sizeof(uint32_t)); - memcpy(mem + 8, code, code_size); - - pos = mem; - address = target_address; - while (length > 0) { - w = length > 256 ? 256 : length; - if (stm32_write_memory(stm, address, pos, w) != STM32_ERR_OK) { - free(mem); - return STM32_ERR_UNKNOWN; - } - - address += w; - pos += w; - length -= w; - } - - free(mem); - return stm32_go(stm, target_address); -} - -stm32_err_t stm32_go(const stm32_t *stm, uint32_t address) -{ - struct port_interface *port = stm->port; - uint8_t buf[5]; - - if (stm->cmd->go == STM32_CMD_ERR) { - fprintf(stderr, "Error: GO command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->go) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - return STM32_ERR_OK; -} - -stm32_err_t stm32_reset_device(const stm32_t *stm) -{ - uint32_t target_address = stm->dev->ram_start; - - return stm32_run_raw_code(stm, target_address, stm_reset_code, stm_reset_code_length); -} - -stm32_err_t stm32_crc_memory(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc) -{ - struct port_interface *port = stm->port; - uint8_t buf[5]; - - if (address & 0x3 || length & 0x3) { - fprintf(stderr, "Start and end addresses must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->crc == STM32_CMD_ERR) { - fprintf(stderr, "Error: CRC command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->crc) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = length >> 24; - buf[1] = (length >> 16) & 0xFF; - buf[2] = (length >> 8) & 0xFF; - buf[3] = length & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (port->read(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (buf[4] != (buf[0] ^ buf[1] ^ buf[2] ^ buf[3])) - return STM32_ERR_UNKNOWN; - - *crc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; - return STM32_ERR_OK; -} - -/* - * CRC computed by STM32 is similar to the standard crc32_be() - * implemented, for example, in Linux kernel in ./lib/crc32.c - * But STM32 computes it on units of 32 bits word and swaps the - * bytes of the word before the computation. - * Due to byte swap, I cannot use any CRC available in existing - * libraries, so here is a simple not optimized implementation. - */ -#define CRCPOLY_BE 0x04c11db7 -#define CRC_MSBMASK 0x80000000 -#define CRC_INIT_VALUE 0xFFFFFFFF -uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len) -{ - int i; - uint32_t data; - - if (len & 0x3) { - fprintf(stderr, "Buffer length must be multiple of 4 bytes\n"); - return 0; - } - - while (len) { - data = *buf++; - data |= *buf++ << 8; - data |= *buf++ << 16; - data |= *buf++ << 24; - len -= 4; - - crc ^= data; - - for (i = 0; i < 32; i++) - if (crc & CRC_MSBMASK) - crc = (crc << 1) ^ CRCPOLY_BE; - else - crc = (crc << 1); - } - return crc; -} - -stm32_err_t stm32_crc_wrapper(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc) -{ - uint8_t buf[256]; - uint32_t start, total_len, len, current_crc; - - if (address & 0x3 || length & 0x3) { - fprintf(stderr, "Start and end addresses must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->crc != STM32_CMD_ERR) - return stm32_crc_memory(stm, address, length, crc); - - start = address; - total_len = length; - current_crc = CRC_INIT_VALUE; - while (length) { - len = length > 256 ? 256 : length; - if (stm32_read_memory(stm, address, buf, len) != STM32_ERR_OK) { - fprintf(stderr, - "Failed to read memory at address 0x%08x, target write-protected?\n", - address); - return STM32_ERR_UNKNOWN; - } - current_crc = stm32_sw_crc(current_crc, buf, len); - length -= len; - address += len; - - fprintf(stderr, - "\rCRC address 0x%08x (%.2f%%) ", - address, - (100.0f / (float)total_len) * (float)(address - start) - ); - fflush(stderr); - } - fprintf(stderr, "Done.\n"); - *crc = current_crc; - return STM32_ERR_OK; -} diff --git a/linux/src/stm32flash_serial/src/stm32.h b/linux/src/stm32flash_serial/src/stm32.h deleted file mode 100644 index 1688fcb4b..000000000 --- a/linux/src/stm32flash_serial/src/stm32.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _STM32_H -#define _STM32_H - -#include -#include "serial.h" - -#define STM32_MAX_RX_FRAME 256 /* cmd read memory */ -#define STM32_MAX_TX_FRAME (1 + 256 + 1) /* cmd write memory */ - -typedef enum { - STM32_ERR_OK = 0, - STM32_ERR_UNKNOWN, /* Generic error */ - STM32_ERR_NACK, - STM32_ERR_NO_CMD, /* Command not available in bootloader */ -} stm32_err_t; - -typedef struct stm32 stm32_t; -typedef struct stm32_cmd stm32_cmd_t; -typedef struct stm32_dev stm32_dev_t; - -struct stm32 { - const serial_t *serial; - struct port_interface *port; - uint8_t bl_version; - uint8_t version; - uint8_t option1, option2; - uint16_t pid; - stm32_cmd_t *cmd; - const stm32_dev_t *dev; -}; - -struct stm32_dev { - uint16_t id; - const char *name; - uint32_t ram_start, ram_end; - uint32_t fl_start, fl_end; - uint16_t fl_pps; // pages per sector - uint16_t fl_ps; // page size - uint32_t opt_start, opt_end; - uint32_t mem_start, mem_end; -}; - -stm32_t *stm32_init(struct port_interface *port, const char init); -void stm32_close(stm32_t *stm); -stm32_err_t stm32_read_memory(const stm32_t *stm, uint32_t address, - uint8_t data[], unsigned int len); -stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address, - const uint8_t data[], unsigned int len); -stm32_err_t stm32_wunprot_memory(const stm32_t *stm); -stm32_err_t stm32_wprot_memory(const stm32_t *stm); -stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, - uint8_t pages); -stm32_err_t stm32_go(const stm32_t *stm, uint32_t address); -stm32_err_t stm32_reset_device(const stm32_t *stm); -stm32_err_t stm32_readprot_memory(const stm32_t *stm); -stm32_err_t stm32_runprot_memory(const stm32_t *stm); -stm32_err_t stm32_crc_memory(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc); -stm32_err_t stm32_crc_wrapper(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc); -uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len); - -#endif - diff --git a/linux/src/stm32flash_serial/src/stm32flash.1 b/linux/src/stm32flash_serial/src/stm32flash.1 deleted file mode 100644 index d37292f6a..000000000 --- a/linux/src/stm32flash_serial/src/stm32flash.1 +++ /dev/null @@ -1,407 +0,0 @@ -.TH STM32FLASH 1 "2013\-11\-03" STM32FLASH "User command" -.SH NAME -stm32flash \- flashing utility for STM32 and STM32W through UART or I2C -.SH SYNOPSIS -.B stm32flash -.RB [ \-cfhjkouvCR ] -.RB [ \-a -.IR bus_address ] -.RB [ \-b -.IR baud_rate ] -.RB [ \-m -.IR serial_mode ] -.RB [ \-r -.IR filename ] -.RB [ \-w -.IR filename ] -.RB [ \-e -.IR num ] -.RB [ \-n -.IR count ] -.RB [ \-g -.IR address ] -.RB [ \-s -.IR start_page ] -.RB [ \-S -.IR address [: length ]] -.RB [ \-F -.IR RX_length [: TX_length ]] -.RB [ \-i -.IR GPIO_string ] -.RI [ tty_device -.R | -.IR i2c_device ] - -.SH DESCRIPTION -.B stm32flash -reads or writes the flash memory of STM32 and STM32W. - -It requires the STM32[W] to embed a bootloader compliant with ST -application note AN3155. -.B stm32flash -uses the serial port -.I tty_device -to interact with the bootloader of STM32[W]. - -.SH OPTIONS -.TP -.BI "\-a" " bus_address" -Specify address on bus for -.IR i2c_device . -This option is mandatory for I2C interface. - -.TP -.BI "\-b" " baud_rate" -Specify baud rate speed of -.IR tty_device . -Please notice that the ST bootloader can automatically detect the baud rate, -as explaned in chapter 2 of AN3155. -This option could be required together with option -.B "\-c" -or if following interaction with bootloader is expected. -Default is -.IR 57600 . - -.TP -.BI "\-m" " mode" -Specify the format of UART data. -.I mode -is a three characters long string where each character specifies, in -this strict order, character size, parity and stop bits. -The only values currenly used are -.I 8e1 -for standard STM32 bootloader and -.I 8n1 -for standard STM32W bootloader. -Default is -.IR 8e1 . - -.TP -.BI "\-r" " filename" -Specify to read the STM32[W] flash and write its content in -.I filename -in raw binary format (see below -.BR "FORMAT CONVERSION" ). - -.TP -.BI "\-w" " filename" -Specify to write the STM32[W] flash with the content of -.IR filename . -File format can be either raw binary or intel hex (see below -.BR "FORMAT CONVERSION" ). -The file format is automatically detected. -To by\-pass format detection and force binary mode (e.g. to -write an intel hex content in STM32[W] flash), use -.B \-f -option. - -.TP -.B \-u -Specify to disable write\-protection from STM32[W] flash. -The STM32[W] will be reset after this operation. - -.TP -.B \-j -Enable the flash read\-protection. - -.TP -.B \-k -Disable the flash read\-protection. - -.TP -.B \-o -Erase only. - -.TP -.BI "\-e" " num" -Specify to erase only -.I num -pages before writing the flash. Default is to erase the whole flash. With -.B \-e 0 -the flash would not be erased. - -.TP -.B \-v -Specify to verify flash content after write operation. - -.TP -.BI "\-n" " count" -Specify to retry failed writes up to -.I count -times. Default is 10 times. - -.TP -.BI "\-g" " address" -Specify address to start execution from (0 = flash start). - -.TP -.BI "\-s" " start_page" -Specify flash page offset (0 = flash start). - -.TP -.BI "\-S" " address" "[:" "length" "]" -Specify start address and optionally length for read/write/erase/crc operations. - -.TP -.BI "\-F" " RX_length" "[:" "TX_length" "]" -Specify the maximum frame size for the current interface. -Due to STM32 bootloader protocol, host will never handle frames bigger than -256 byte in RX or 258 byte in TX. -Due to current code, lowest limit in RX is 20 byte (to read a complete reply -of command GET). Minimum limit in TX is 5 byte, required by protocol. - -.TP -.B \-f -Force binary parser while reading file with -.BR "\-w" "." - -.TP -.B \-h -Show help. - -.TP -.B \-c -Specify to resume the existing UART connection and don't send initial -INIT sequence to detect baud rate. Baud rate must be kept the same as the -existing connection. This is useful if the reset fails. - -.TP -.BI "\-i" " GPIO_string" -Specify the GPIO sequences on the host to force STM32[W] to enter and -exit bootloader mode. GPIO can either be real GPIO connected from host to -STM32[W] beside the UART connection, or UART's modem signals used as -GPIO. (See below -.B BOOTLOADER GPIO SEQUENCE -for the format of -.I GPIO_string -and further explanation). - -.TP -.B \-C -Specify to compute CRC on memory content. -By default the CRC is computed on the whole flash content. -Use -.B "\-S" -to provide different memory address range. - -.TP -.B \-R -Specify to reset the device at exit. -This option is ignored if either -.BR "\-g" "," -.BR "\-j" "," -.B "\-k" -or -.B "\-u" -is also specified. - -.SH BOOTLOADER GPIO SEQUENCE -This feature is currently available on Linux host only. - -As explained in ST application note AN2606, after reset the STM32 will -execute either the application program in user flash or the bootloader, -depending on the level applied at specific pins of STM32 during reset. - -STM32 bootloader is automatically activated by configuring the pins -BOOT0="high" and BOOT1="low" and then by applying a reset. -Application program in user flash is activated by configuring the pin -BOOT0="low" (the level on BOOT1 is ignored) and then by applying a reset. - -When GPIO from host computer are connected to either configuration and -reset pins of STM32, -.B stm32flash -can control the host GPIO to reset STM32 and to force execution of -bootloader or execution of application program. - -The sequence of GPIO values to entry to and exit from bootloader mode is -provided with command line option -.B "\-i" -.IR "GPIO_string" . - -.PD 0 -The format of -.IR "GPIO_string" " is:" -.RS -GPIO_string = [entry sequence][:[exit sequence]] -.P -sequence = [\-]n[,sequence] -.RE -.P -In the above sequences, negative numbers correspond to GPIO at "low" level; -numbers without sign correspond to GPIO at "high" level. -The value "n" can either be the GPIO number on the host system or the -string "rts", "dtr" or "brk". The strings "rts" and "dtr" drive the -corresponding UART's modem lines RTS and DTR as GPIO. -The string "brk" forces the UART to send a BREAK sequence on TX line; -after BREAK the UART is returned in normal "non\-break" mode. -Note: the string "\-brk" has no effect and is ignored. -.PD - -.PD 0 -As example, let's suppose the following connection between host and STM32: -.IP \(bu 2 -host GPIO_3 connected to reset pin of STM32; -.IP \(bu 2 -host GPIO_4 connected to STM32 pin BOOT0; -.IP \(bu 2 -host GPIO_5 connected to STM32 pin BOOT1. -.PD -.P - -In this case, the sequence to enter in bootloader mode is: first put -GPIO_4="high" and GPIO_5="low"; then send reset pulse by GPIO_3="low" -followed by GPIO_3="high". -The corresponding string for -.I GPIO_string -is "4,\-5,\-3,3". - -To exit from bootloade and run the application program, the sequence is: -put GPIO_4="low"; then send reset pulse. -The corresponding string for -.I GPIO_string -is "\-4,\-3,3". - -The complete command line flag is "\-i 4,\-5,\-3,3:\-4,\-3,3". - -STM32W uses pad PA5 to select boot mode; if during reset PA5 is "low" then -STM32W will enter in bootloader mode; if PA5 is "high" it will execute the -program in flash. - -As example, supposing GPIO_3 connected to PA5 and GPIO_2 to STM32W's reset. -The command: -.PD 0 -.RS -stm32flash \-i \-3,\-2,2:3,\-2,2 /dev/ttyS0 -.RE -provides: -.IP \(bu 2 -entry sequence: GPIO_3=low, GPIO_2=low, GPIO_2=high -.IP \(bu 2 -exit sequence: GPIO_3=high, GPIO_2=low, GPIO_2=high -.PD - -.SH EXAMPLES -Get device information: -.RS -.PD 0 -.P -stm32flash /dev/ttyS0 -.PD -.RE - -Write with verify and then start execution: -.RS -.PD 0 -.P -stm32flash \-w filename \-v \-g 0x0 /dev/ttyS0 -.PD -.RE - -Read flash to file: -.RS -.PD 0 -.P -stm32flash \-r filename /dev/ttyS0 -.PD -.RE - -Start execution: -.RS -.PD 0 -.P -stm32flash \-g 0x0 /dev/ttyS0 -.PD -.RE - -Specify: -.PD 0 -.IP \(bu 2 -entry sequence: RTS=low, DTR=low, DTR=high -.IP \(bu 2 -exit sequence: RTS=high, DTR=low, DTR=high -.P -.RS -stm32flash \-i \-rts,\-dtr,dtr:rts,\-dtr,dtr /dev/ttyS0 -.PD -.RE - -.SH FORMAT CONVERSION -Flash images provided by ST or created with ST tools are often in file -format Motorola S\-Record. -Conversion between raw binary, intel hex and Motorola S\-Record can be -done through software package SRecord. - -.SH AUTHORS -The original software package -.B stm32flash -is written by -.I Geoffrey McRae -and is since 2012 maintained by -.IR "Tormod Volden " . - -Man page and extension to STM32W and I2C are written by -.IR "Antonio Borneo " . - -Please report any bugs at the project homepage -http://stm32flash.googlecode.com . - -.SH SEE ALSO -.BR "srec_cat" "(1)," " srec_intel" "(5)," " srec_motorola" "(5)." - -The communication protocol used by ST bootloader is documented in -following ST application notes, depending on communication port. -The current version of -.B stm32flash -only supports -.I UART -and -.I I2C -ports. -.PD 0 -.P -.IP \(bu 2 -AN3154: CAN protocol used in the STM32 bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/CD00264321.pdf -.RE - -.P -.IP \(bu 2 -AN3155: USART protocol used in the STM32(TM) bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/CD00264342.pdf -.RE - -.P -.IP \(bu 2 -AN4221: I2C protocol used in the STM32 bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/DM00072315.pdf -.RE - -.P -.IP \(bu 2 -AN4286: SPI protocol used in the STM32 bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/DM00081379.pdf -.RE - -.PD - - -Boot mode selection for STM32 is documented in ST application note -AN2606, available from the ST website: -.PD 0 -.P -http://www.st.com/web/en/resource/technical/document/application_note/CD00167594.pdf -.PD - -.SH LICENSE -.B stm32flash -is distributed under GNU GENERAL PUBLIC LICENSE Version 2. -Copy of the license is available within the source code in the file -.IR "gpl\-2.0.txt" . diff --git a/linux/src/stm32flash_serial/src/utils.c b/linux/src/stm32flash_serial/src/utils.c deleted file mode 100644 index 271bb3ed7..000000000 --- a/linux/src/stm32flash_serial/src/utils.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include "utils.h" - -/* detect CPU endian */ -char cpu_le() { - const uint32_t cpu_le_test = 0x12345678; - return ((const unsigned char*)&cpu_le_test)[0] == 0x78; -} - -uint32_t be_u32(const uint32_t v) { - if (cpu_le()) - return ((v & 0xFF000000) >> 24) | - ((v & 0x00FF0000) >> 8) | - ((v & 0x0000FF00) << 8) | - ((v & 0x000000FF) << 24); - return v; -} - -uint32_t le_u32(const uint32_t v) { - if (!cpu_le()) - return ((v & 0xFF000000) >> 24) | - ((v & 0x00FF0000) >> 8) | - ((v & 0x0000FF00) << 8) | - ((v & 0x000000FF) << 24); - return v; -} diff --git a/linux/src/stm32flash_serial/src/utils.h b/linux/src/stm32flash_serial/src/utils.h deleted file mode 100644 index a8d37d2d5..000000000 --- a/linux/src/stm32flash_serial/src/utils.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _H_UTILS -#define _H_UTILS - -#include - -char cpu_le(); -uint32_t be_u32(const uint32_t v); -uint32_t le_u32(const uint32_t v); - -#endif diff --git a/linux64/src/stm32flash_serial/src/AUTHORS b/linux64/src/stm32flash_serial/src/AUTHORS deleted file mode 100644 index d096f2205..000000000 --- a/linux64/src/stm32flash_serial/src/AUTHORS +++ /dev/null @@ -1,19 +0,0 @@ -Authors ordered by first contribution. - -Geoffrey McRae -Bret Olmsted -Tormod Volden -Jakob Malm -Reuben Dowle -Matthias Kubisch -Paul Fertser -Daniel Strnad -Jérémie Rapin -Christian Pointner -Mats Erik Andersson -Alexey Borovik -Antonio Borneo -Armin van der Togt -Brian Silverman -Georg Hofmann -Luis Rodrigues diff --git a/linux64/src/stm32flash_serial/src/Android.mk b/linux64/src/stm32flash_serial/src/Android.mk deleted file mode 100644 index 7be3d0018..000000000 --- a/linux64/src/stm32flash_serial/src/Android.mk +++ /dev/null @@ -1,20 +0,0 @@ -TOP_LOCAL_PATH := $(call my-dir) - -include $(call all-named-subdir-makefiles, parsers) - -LOCAL_PATH := $(TOP_LOCAL_PATH) - -include $(CLEAR_VARS) -LOCAL_MODULE := stm32flash -LOCAL_SRC_FILES := \ - dev_table.c \ - i2c.c \ - init.c \ - main.c \ - port.c \ - serial_common.c \ - serial_platform.c \ - stm32.c \ - utils.c -LOCAL_STATIC_LIBRARIES := libparsers -include $(BUILD_EXECUTABLE) diff --git a/linux64/src/stm32flash_serial/src/HOWTO b/linux64/src/stm32flash_serial/src/HOWTO deleted file mode 100644 index d8f32eb04..000000000 --- a/linux64/src/stm32flash_serial/src/HOWTO +++ /dev/null @@ -1,35 +0,0 @@ -Add new interfaces: -===================================================================== -Current version 0.4 supports the following interfaces: -- UART Windows (either "COMn" and "\\.\COMn"); -- UART posix/Linux (e.g. "/dev/ttyUSB0"); -- I2C Linux through standard driver "i2c-dev" (e.g. "/dev/i2c-n"). - -Starting from version 0.4, the back-end of stm32flash is modular and -ready to be expanded to support new interfaces. -I'm planning adding SPI on Linux through standard driver "spidev". -You are invited to contribute with more interfaces. - -To add a new interface you need to add a new file, populate the struct -port_interface (check at the end of files i2c.c, serial_posix.c and -serial_w32.c) and provide the relative functions to operate on the -interface: open/close, read/write, get_cfg_str and the optional gpio. -The include the new drive in Makefile and register the new struct -port_interface in file port.c in struct port_interface *ports[]. - -There are several USB-I2C adapter in the market, each providing its -own libraries to communicate with the I2C bus. -Could be interesting to provide as back-end a bridge between stm32flash -and such libraries (I have no plan on this item). - - -Add new STM32 devices: -===================================================================== -Add a new line in file dev_table.c, in table devices[]. -The fields of the table are listed in stm32.h, struct stm32_dev. - - -Cross compile on Linux host for Windows target with MinGW: -===================================================================== -I'm using a 64 bit Arch Linux machines, and I usually run: - make CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-ar diff --git a/linux64/src/stm32flash_serial/src/I2C.txt b/linux64/src/stm32flash_serial/src/I2C.txt deleted file mode 100644 index 4c05ff62d..000000000 --- a/linux64/src/stm32flash_serial/src/I2C.txt +++ /dev/null @@ -1,94 +0,0 @@ -About I2C back-end communication in stm32flash -========================================================================== - -Starting from version v0.4, beside the serial communication port, -stm32flash adds support for I2C port to talk with STM32 bootloader. - -The current I2C back-end supports only the API provided by Linux kernel -driver "i2c-dev", so only I2C controllers with Linux kernel driver can be -used. -In Linux source code, most of the drivers for I2C and SMBUS controllers -are in - ./drivers/i2c/busses/ -Only I2C is supported by STM32 bootloader, so check the section below -about SMBUS. -No I2C support for Windows is available in stm32flash v0.4. - -Thanks to the new modular back-end, stm32flash can be easily extended to -support new back-ends and API. Check HOWTO file in stm32flash source code -for details. - -In the market there are several USB-to-I2C dongles; most of them are not -supported by kernel drivers. Manufacturer provide proprietary userspace -libraries using not standardized API. -These API and dongles could be supported in feature versions. - -There are currently 3 versions of STM32 bootloader for I2C communications: -- v1.0 using I2C clock stretching synchronization between host and STM32; -- v1.1 superset of v1.0, adds non stretching commands; -- v1.2 superset of v1.1, adds CRC command and compatibility with i2cdetect. -Details in ST application note AN2606. -All the bootloaders above are tested and working with stm32flash. - - -SMBUS controllers -========================================================================== - -Almost 50% of the drivers in Linux source code folder - ./drivers/i2c/busses/ -are for controllers that "only" support SMBUS protocol. They can NOT -operate with STM32 bootloader. -To identify if your controller supports I2C, use command: - i2cdetect -F n -where "n" is the number of the I2C interface (e.g. n=3 for "/dev/i2c-3"). -Controllers that supports I2C will report - I2C yes -Controller that support both I2C and SMBUS are ok. - -If you are interested on details about SMBUS protocol, you can download -the current specs from - http://smbus.org/specs/smbus20.pdf -and you can read the files in Linux source code - ./Documentation/i2c/i2c-protocol - ./Documentation/i2c/smbus-protocol - - -About bootloader v1.0 -========================================================================== - -Version v1.0 can have issues with some I2C controllers due to use of clock -stretching during commands that require long operations, like flash erase -and programming. - -Clock stretching is a technique to synchronize host and I2C device. When -I2C device wants to force a delay in the communication, it push "low" the -I2C clock; the I2C controller detects it and waits until I2C clock returns -"high". -Most I2C controllers set a "timeout" for clock stretching, ranging from -few milli-seconds to seconds depending on specific HW or SW driver. - -It is possible that the timeout in your I2C controller is smaller than the -delay required for flash erase or programming. In this case the I2C -controller will timeout and report error to stm32flash. -There is no possibility for stm32flash to retry, so it can only signal the -error and exit. - -To by-pass the issue with bootloader v1.0 you can modify the kernel driver -of your I2C controller. Not an easy job, since every controller has its own -way to handle the timeout. - -In my case I'm using the I2C controller integrated in the VGA port of my -laptop HP EliteBook 8460p. I built the 0.25$ VGA-to-I2C adapter reported in - http://www.paintyourdragon.com/?p=43 -To change the timeout of the I2C controller I had to modify the kernel file - drivers/gpu/drm/radeon/radeon_i2c.c -line 969 -- i2c->bit.timeout = usecs_to_jiffies(2200); /* from VESA */ -+ i2c->bit.timeout = msecs_to_jiffies(5000); /* 5s for STM32 */ -and recompile it. -Then - $> modprobe i2c-dev - $> chmod 666 /dev/i2c-7 - #> stm32flash -a 0x39 /dev/i2c-7 - -2014-09-16 Antonio Borneo diff --git a/linux64/src/stm32flash_serial/src/Makefile b/linux64/src/stm32flash_serial/src/Makefile deleted file mode 100644 index 0328d5588..000000000 --- a/linux64/src/stm32flash_serial/src/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -PREFIX = /usr/local -CFLAGS += -Wall -g - -INSTALL = install - -OBJS = dev_table.o \ - i2c.o \ - init.o \ - main.o \ - port.o \ - serial_common.o \ - serial_platform.o \ - stm32.o \ - utils.o - -LIBOBJS = parsers/parsers.a - -all: stm32flash - -serial_platform.o: serial_posix.c serial_w32.c - -parsers/parsers.a: - cd parsers && $(MAKE) parsers.a - -stm32flash: $(OBJS) $(LIBOBJS) - $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBOBJS) - -clean: - rm -f $(OBJS) stm32flash - cd parsers && $(MAKE) $@ - -install: all - $(INSTALL) -d $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -m 755 stm32flash $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -d $(DESTDIR)$(PREFIX)/share/man/man1 - $(INSTALL) -m 644 stm32flash.1 $(DESTDIR)$(PREFIX)/share/man/man1 - -.PHONY: all clean install diff --git a/linux64/src/stm32flash_serial/src/TODO b/linux64/src/stm32flash_serial/src/TODO deleted file mode 100644 index 41df614ff..000000000 --- a/linux64/src/stm32flash_serial/src/TODO +++ /dev/null @@ -1,7 +0,0 @@ - -stm32: -- Add support for variable page size - -AUTHORS: -- Add contributors from Geoffrey's commits - diff --git a/linux64/src/stm32flash_serial/src/dev_table.c b/linux64/src/stm32flash_serial/src/dev_table.c deleted file mode 100644 index 399cd9d08..000000000 --- a/linux64/src/stm32flash_serial/src/dev_table.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "stm32.h" - -/* - * Device table, corresponds to the "Bootloader device-dependant parameters" - * table in ST document AN2606. - * Note that the option bytes upper range is inclusive! - */ -const stm32_dev_t devices[] = { - /* F0 */ - {0x440, "STM32F051xx" , 0x20001000, 0x20002000, 0x08000000, 0x08010000, 4, 1024, 0x1FFFF800, 0x1FFFF80B, 0x1FFFEC00, 0x1FFFF800}, - {0x444, "STM32F030/F031" , 0x20001000, 0x20002000, 0x08000000, 0x08010000, 4, 1024, 0x1FFFF800, 0x1FFFF80B, 0x1FFFEC00, 0x1FFFF800}, - {0x445, "STM32F042xx" , 0x20001800, 0x20001800, 0x08000000, 0x08008000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFC400, 0x1FFFF800}, - {0x448, "STM32F072xx" , 0x20001800, 0x20004000, 0x08000000, 0x08020000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFC800, 0x1FFFF800}, - /* F1 */ - {0x412, "Low-density" , 0x20000200, 0x20002800, 0x08000000, 0x08008000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x410, "Medium-density" , 0x20000200, 0x20005000, 0x08000000, 0x08020000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x414, "High-density" , 0x20000200, 0x20010000, 0x08000000, 0x08080000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x420, "Medium-density VL" , 0x20000200, 0x20002000, 0x08000000, 0x08020000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x428, "High-density VL" , 0x20000200, 0x20008000, 0x08000000, 0x08080000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x418, "Connectivity line" , 0x20001000, 0x20010000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFB000, 0x1FFFF800}, - {0x430, "XL-density" , 0x20000800, 0x20018000, 0x08000000, 0x08100000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFE000, 0x1FFFF800}, - /* Note that F2 and F4 devices have sectors of different page sizes - and only the first sectors (of one page size) are included here */ - /* F2 */ - {0x411, "STM32F2xx" , 0x20002000, 0x20020000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77DF}, - /* F3 */ - {0x432, "STM32F373/8" , 0x20001400, 0x20008000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - {0x422, "F302xB/303xB/358" , 0x20001400, 0x20010000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - {0x439, "STM32F302x4(6/8)" , 0x20001800, 0x20004000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - {0x438, "F303x4/334/328" , 0x20001800, 0x20003000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - /* F4 */ - {0x413, "STM32F40/1" , 0x20002000, 0x20020000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77DF}, - /* 0x419 is also used for STM32F429/39 but with other bootloader ID... */ - {0x419, "STM32F427/37" , 0x20002000, 0x20030000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF}, - {0x423, "STM32F401xB(C)" , 0x20003000, 0x20010000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF}, - {0x433, "STM32F401xD(E)" , 0x20003000, 0x20018000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF}, - /* L0 */ - {0x417, "L05xxx/06xxx" , 0x20001000, 0x20002000, 0x08000000, 0x08010000, 32, 128, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000}, - /* L1 */ - {0x416, "L1xxx6(8/B)" , 0x20000800, 0x20004000, 0x08000000, 0x08020000, 16, 256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000}, - {0x429, "L1xxx6(8/B)A" , 0x20001000, 0x20008000, 0x08000000, 0x08020000, 16, 256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000}, - {0x427, "L1xxxC" , 0x20001000, 0x20008000, 0x08000000, 0x08020000, 16, 256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF02000}, - {0x436, "L1xxxD" , 0x20001000, 0x2000C000, 0x08000000, 0x08060000, 16, 256, 0x1ff80000, 0x1ff8000F, 0x1FF00000, 0x1FF02000}, - {0x437, "L1xxxE" , 0x20001000, 0x20014000, 0x08000000, 0x08060000, 16, 256, 0x1ff80000, 0x1ff8000F, 0x1FF00000, 0x1FF02000}, - /* These are not (yet) in AN2606: */ - {0x641, "Medium_Density PL" , 0x20000200, 0x00005000, 0x08000000, 0x08020000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x9a8, "STM32W-128K" , 0x20000200, 0x20002000, 0x08000000, 0x08020000, 1, 1024, 0, 0, 0, 0}, - {0x9b0, "STM32W-256K" , 0x20000200, 0x20004000, 0x08000000, 0x08040000, 1, 2048, 0, 0, 0, 0}, - {0x0} -}; diff --git a/linux64/src/stm32flash_serial/src/gpl-2.0.txt b/linux64/src/stm32flash_serial/src/gpl-2.0.txt deleted file mode 100644 index d159169d1..000000000 --- a/linux64/src/stm32flash_serial/src/gpl-2.0.txt +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 2 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, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/linux64/src/stm32flash_serial/src/i2c.c b/linux64/src/stm32flash_serial/src/i2c.c deleted file mode 100644 index 10e6bb15a..000000000 --- a/linux64/src/stm32flash_serial/src/i2c.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "serial.h" -#include "port.h" - - -#if !defined(__linux__) - -static port_err_t i2c_open(struct port_interface *port, - struct port_options *ops) -{ - return PORT_ERR_NODEV; -} - -struct port_interface port_i2c = { - .name = "i2c", - .open = i2c_open, -}; - -#else - -#ifdef __ANDROID__ -#define I2C_SLAVE 0x0703 /* Use this slave address */ -#define I2C_FUNCS 0x0705 /* Get the adapter functionality mask */ -/* To determine what functionality is present */ -#define I2C_FUNC_I2C 0x00000001 -#else -#include -#include -#endif - -#include - -struct i2c_priv { - int fd; - int addr; -}; - -static port_err_t i2c_open(struct port_interface *port, - struct port_options *ops) -{ - struct i2c_priv *h; - int fd, addr, ret; - unsigned long funcs; - - /* 1. check device name match */ - if (strncmp(ops->device, "/dev/i2c-", strlen("/dev/i2c-"))) - return PORT_ERR_NODEV; - - /* 2. check options */ - addr = ops->bus_addr; - if (addr < 0x03 || addr > 0x77) { - fprintf(stderr, "I2C address out of range [0x03-0x77]\n"); - return PORT_ERR_UNKNOWN; - } - - /* 3. open it */ - h = calloc(sizeof(*h), 1); - if (h == NULL) { - fprintf(stderr, "End of memory\n"); - return PORT_ERR_UNKNOWN; - } - fd = open(ops->device, O_RDWR); - if (fd < 0) { - fprintf(stderr, "Unable to open special file \"%s\"\n", - ops->device); - free(h); - return PORT_ERR_UNKNOWN; - } - - /* 3.5. Check capabilities */ - ret = ioctl(fd, I2C_FUNCS, &funcs); - if (ret < 0) { - fprintf(stderr, "I2C ioctl(funcs) error %d\n", errno); - close(fd); - free(h); - return PORT_ERR_UNKNOWN; - } - if ((funcs & I2C_FUNC_I2C) == 0) { - fprintf(stderr, "Error: controller is not I2C, only SMBUS.\n"); - close(fd); - free(h); - return PORT_ERR_UNKNOWN; - } - - /* 4. set options */ - ret = ioctl(fd, I2C_SLAVE, addr); - if (ret < 0) { - fprintf(stderr, "I2C ioctl(slave) error %d\n", errno); - close(fd); - free(h); - return PORT_ERR_UNKNOWN; - } - - h->fd = fd; - h->addr = addr; - port->private = h; - return PORT_ERR_OK; -} - -static port_err_t i2c_close(struct port_interface *port) -{ - struct i2c_priv *h; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - close(h->fd); - free(h); - port->private = NULL; - return PORT_ERR_OK; -} - -static port_err_t i2c_read(struct port_interface *port, void *buf, - size_t nbyte) -{ - struct i2c_priv *h; - int ret; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - ret = read(h->fd, buf, nbyte); - if (ret != nbyte) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; -} - -static port_err_t i2c_write(struct port_interface *port, void *buf, - size_t nbyte) -{ - struct i2c_priv *h; - int ret; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - ret = write(h->fd, buf, nbyte); - if (ret != nbyte) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; -} - -static port_err_t i2c_gpio(struct port_interface *port, serial_gpio_t n, - int level) -{ - return PORT_ERR_OK; -} - -static const char *i2c_get_cfg_str(struct port_interface *port) -{ - struct i2c_priv *h; - static char str[11]; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return "INVALID"; - snprintf(str, sizeof(str), "addr 0x%2x", h->addr); - return str; -} - -static struct varlen_cmd i2c_cmd_get_reply[] = { - {0x10, 11}, - {0x11, 17}, - {0x12, 18}, - { /* sentinel */ } -}; - -struct port_interface port_i2c = { - .name = "i2c", - .flags = PORT_STRETCH_W, - .open = i2c_open, - .close = i2c_close, - .read = i2c_read, - .write = i2c_write, - .gpio = i2c_gpio, - .cmd_get_reply = i2c_cmd_get_reply, - .get_cfg_str = i2c_get_cfg_str, -}; - -#endif diff --git a/linux64/src/stm32flash_serial/src/init.c b/linux64/src/stm32flash_serial/src/init.c deleted file mode 100644 index 77a571bd8..000000000 --- a/linux64/src/stm32flash_serial/src/init.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2013 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "init.h" -#include "serial.h" -#include "stm32.h" -#include "port.h" - -struct gpio_list { - struct gpio_list *next; - int gpio; -}; - - -static int write_to(const char *filename, const char *value) -{ - int fd, ret; - - fd = open(filename, O_WRONLY); - if (fd < 0) { - fprintf(stderr, "Cannot open file \"%s\"\n", filename); - return 0; - } - ret = write(fd, value, strlen(value)); - if (ret < 0) { - fprintf(stderr, "Error writing in file \"%s\"\n", filename); - close(fd); - return 0; - } - close(fd); - return 1; -} - -#if !defined(__linux__) -static int drive_gpio(int n, int level, struct gpio_list **gpio_to_release) -{ - fprintf(stderr, "GPIO control only available in Linux\n"); - return 0; -} -#else -static int drive_gpio(int n, int level, struct gpio_list **gpio_to_release) -{ - char num[16]; /* sized to carry MAX_INT */ - char file[48]; /* sized to carry longest filename */ - struct stat buf; - struct gpio_list *new; - int ret; - - sprintf(file, "/sys/class/gpio/gpio%d/direction", n); - ret = stat(file, &buf); - if (ret) { - /* file miss, GPIO not exported yet */ - sprintf(num, "%d", n); - ret = write_to("/sys/class/gpio/export", num); - if (!ret) - return 0; - ret = stat(file, &buf); - if (ret) { - fprintf(stderr, "GPIO %d not available\n", n); - return 0; - } - new = (struct gpio_list *)malloc(sizeof(struct gpio_list)); - if (new == NULL) { - fprintf(stderr, "Out of memory\n"); - return 0; - } - new->gpio = n; - new->next = *gpio_to_release; - *gpio_to_release = new; - } - - return write_to(file, level ? "high" : "low"); -} -#endif - -static int release_gpio(int n) -{ - char num[16]; /* sized to carry MAX_INT */ - - sprintf(num, "%d", n); - return write_to("/sys/class/gpio/unexport", num); -} - -static int gpio_sequence(struct port_interface *port, const char *s, size_t l) -{ - struct gpio_list *gpio_to_release = NULL, *to_free; - int ret, level, gpio; - - ret = 1; - while (ret == 1 && *s && l > 0) { - if (*s == '-') { - level = 0; - s++; - l--; - } else - level = 1; - - if (isdigit(*s)) { - gpio = atoi(s); - while (isdigit(*s)) { - s++; - l--; - } - } else if (!strncmp(s, "rts", 3)) { - gpio = -GPIO_RTS; - s += 3; - l -= 3; - } else if (!strncmp(s, "dtr", 3)) { - gpio = -GPIO_DTR; - s += 3; - l -= 3; - } else if (!strncmp(s, "brk", 3)) { - gpio = -GPIO_BRK; - s += 3; - l -= 3; - } else { - fprintf(stderr, "Character \'%c\' is not a digit\n", *s); - ret = 0; - break; - } - - if (*s && (l > 0)) { - if (*s == ',') { - s++; - l--; - } else { - fprintf(stderr, "Character \'%c\' is not a separator\n", *s); - ret = 0; - break; - } - } - if (gpio < 0) - ret = (port->gpio(port, -gpio, level) == PORT_ERR_OK); - else - ret = drive_gpio(gpio, level, &gpio_to_release); - usleep(100000); - } - - while (gpio_to_release) { - release_gpio(gpio_to_release->gpio); - to_free = gpio_to_release; - gpio_to_release = gpio_to_release->next; - free(to_free); - } - usleep(500000); - return ret; -} - -static int gpio_bl_entry(struct port_interface *port, const char *seq) -{ - char *s; - - if (seq == NULL || seq[0] == ':') - return 1; - - s = strchr(seq, ':'); - if (s == NULL) - return gpio_sequence(port, seq, strlen(seq)); - - return gpio_sequence(port, seq, s - seq); -} - -static int gpio_bl_exit(struct port_interface *port, const char *seq) -{ - char *s; - - if (seq == NULL) - return 1; - - s = strchr(seq, ':'); - if (s == NULL || s[1] == '\0') - return 1; - - return gpio_sequence(port, s + 1, strlen(s + 1)); -} - -int init_bl_entry(struct port_interface *port, const char *seq) -{ - if (seq) - return gpio_bl_entry(port, seq); - - return 1; -} - -int init_bl_exit(stm32_t *stm, struct port_interface *port, const char *seq) -{ - if (seq) - return gpio_bl_exit(port, seq); - - if (stm32_reset_device(stm) != STM32_ERR_OK) - return 0; - return 1; -} diff --git a/linux64/src/stm32flash_serial/src/init.h b/linux64/src/stm32flash_serial/src/init.h deleted file mode 100644 index 6075b519b..000000000 --- a/linux64/src/stm32flash_serial/src/init.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2013 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _INIT_H -#define _INIT_H - -#include "stm32.h" -#include "port.h" - -int init_bl_entry(struct port_interface *port, const char *seq); -int init_bl_exit(stm32_t *stm, struct port_interface *port, const char *seq); - -#endif diff --git a/linux64/src/stm32flash_serial/src/main.c b/linux64/src/stm32flash_serial/src/main.c deleted file mode 100644 index f081d6131..000000000 --- a/linux64/src/stm32flash_serial/src/main.c +++ /dev/null @@ -1,774 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright 2010 Geoffrey McRae - Copyright 2011 Steve Markgraf - Copyright 2012 Tormod Volden - Copyright 2013 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "init.h" -#include "utils.h" -#include "serial.h" -#include "stm32.h" -#include "parsers/parser.h" -#include "port.h" - -#include "parsers/binary.h" -#include "parsers/hex.h" - -#define VERSION "Arduino_STM32_0.9" - -/* device globals */ -stm32_t *stm = NULL; - -void *p_st = NULL; -parser_t *parser = NULL; - -/* settings */ -struct port_options port_opts = { - .device = NULL, - .baudRate = SERIAL_BAUD_57600, - .serial_mode = "8e1", - .bus_addr = 0, - .rx_frame_max = STM32_MAX_RX_FRAME, - .tx_frame_max = STM32_MAX_TX_FRAME, -}; -int rd = 0; -int wr = 0; -int wu = 0; -int rp = 0; -int ur = 0; -int eraseOnly = 0; -int crc = 0; -int npages = 0; -int spage = 0; -int no_erase = 0; -char verify = 0; -int retry = 10; -char exec_flag = 0; -uint32_t execute = 0; -char init_flag = 1; -char force_binary = 0; -char reset_flag = 0; -char *filename; -char *gpio_seq = NULL; -uint32_t start_addr = 0; -uint32_t readwrite_len = 0; - -/* functions */ -int parse_options(int argc, char *argv[]); -void show_help(char *name); - -static int is_addr_in_ram(uint32_t addr) -{ - return addr >= stm->dev->ram_start && addr < stm->dev->ram_end; -} - -static int is_addr_in_flash(uint32_t addr) -{ - return addr >= stm->dev->fl_start && addr < stm->dev->fl_end; -} - -static int flash_addr_to_page_floor(uint32_t addr) -{ - if (!is_addr_in_flash(addr)) - return 0; - - return (addr - stm->dev->fl_start) / stm->dev->fl_ps; -} - -static int flash_addr_to_page_ceil(uint32_t addr) -{ - if (!(addr >= stm->dev->fl_start && addr <= stm->dev->fl_end)) - return 0; - - return (addr + stm->dev->fl_ps - 1 - stm->dev->fl_start) - / stm->dev->fl_ps; -} - -static uint32_t flash_page_to_addr(int page) -{ - return stm->dev->fl_start + page * stm->dev->fl_ps; -} - -int main(int argc, char* argv[]) { - struct port_interface *port = NULL; - int ret = 1; - stm32_err_t s_err; - parser_err_t perr; - FILE *diag = stdout; - - fprintf(diag, "stm32flash " VERSION "\n\n"); - fprintf(diag, "http://github.com/rogerclarkmelbourne/arduino_stm32\n\n"); - if (parse_options(argc, argv) != 0) - goto close; - - if (rd && filename[0] == '-') { - diag = stderr; - } - - if (wr) { - /* first try hex */ - if (!force_binary) { - parser = &PARSER_HEX; - p_st = parser->init(); - if (!p_st) { - fprintf(stderr, "%s Parser failed to initialize\n", parser->name); - goto close; - } - } - - if (force_binary || (perr = parser->open(p_st, filename, 0)) != PARSER_ERR_OK) { - if (force_binary || perr == PARSER_ERR_INVALID_FILE) { - if (!force_binary) { - parser->close(p_st); - p_st = NULL; - } - - /* now try binary */ - parser = &PARSER_BINARY; - p_st = parser->init(); - if (!p_st) { - fprintf(stderr, "%s Parser failed to initialize\n", parser->name); - goto close; - } - perr = parser->open(p_st, filename, 0); - } - - /* if still have an error, fail */ - if (perr != PARSER_ERR_OK) { - fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr)); - if (perr == PARSER_ERR_SYSTEM) perror(filename); - goto close; - } - } - - fprintf(diag, "Using Parser : %s\n", parser->name); - } else { - parser = &PARSER_BINARY; - p_st = parser->init(); - if (!p_st) { - fprintf(stderr, "%s Parser failed to initialize\n", parser->name); - goto close; - } - } - - if (port_open(&port_opts, &port) != PORT_ERR_OK) { - fprintf(stderr, "Failed to open port: %s\n", port_opts.device); - goto close; - } - - fprintf(diag, "Interface %s: %s\n", port->name, port->get_cfg_str(port)); - if (init_flag && init_bl_entry(port, gpio_seq) == 0) - goto close; - stm = stm32_init(port, init_flag); - if (!stm) - goto close; - - fprintf(diag, "Version : 0x%02x\n", stm->bl_version); - if (port->flags & PORT_GVR_ETX) { - fprintf(diag, "Option 1 : 0x%02x\n", stm->option1); - fprintf(diag, "Option 2 : 0x%02x\n", stm->option2); - } - fprintf(diag, "Device ID : 0x%04x (%s)\n", stm->pid, stm->dev->name); - fprintf(diag, "- RAM : %dKiB (%db reserved by bootloader)\n", (stm->dev->ram_end - 0x20000000) / 1024, stm->dev->ram_start - 0x20000000); - fprintf(diag, "- Flash : %dKiB (sector size: %dx%d)\n", (stm->dev->fl_end - stm->dev->fl_start ) / 1024, stm->dev->fl_pps, stm->dev->fl_ps); - fprintf(diag, "- Option RAM : %db\n", stm->dev->opt_end - stm->dev->opt_start + 1); - fprintf(diag, "- System RAM : %dKiB\n", (stm->dev->mem_end - stm->dev->mem_start) / 1024); - - uint8_t buffer[256]; - uint32_t addr, start, end; - unsigned int len; - int failed = 0; - int first_page, num_pages; - - /* - * Cleanup addresses: - * - * Starting from options - * start_addr, readwrite_len, spage, npages - * and using device memory size, compute - * start, end, first_page, num_pages - */ - if (start_addr || readwrite_len) { - start = start_addr; - - if (is_addr_in_flash(start)) - end = stm->dev->fl_end; - else { - no_erase = 1; - if (is_addr_in_ram(start)) - end = stm->dev->ram_end; - else - end = start + sizeof(uint32_t); - } - - if (readwrite_len && (end > start + readwrite_len)) - end = start + readwrite_len; - - first_page = flash_addr_to_page_floor(start); - if (!first_page && end == stm->dev->fl_end) - num_pages = 0xff; /* mass erase */ - else - num_pages = flash_addr_to_page_ceil(end) - first_page; - } else if (!spage && !npages) { - start = stm->dev->fl_start; - end = stm->dev->fl_end; - first_page = 0; - num_pages = 0xff; /* mass erase */ - } else { - first_page = spage; - start = flash_page_to_addr(first_page); - if (start > stm->dev->fl_end) { - fprintf(stderr, "Address range exceeds flash size.\n"); - goto close; - } - - if (npages) { - num_pages = npages; - end = flash_page_to_addr(first_page + num_pages); - if (end > stm->dev->fl_end) - end = stm->dev->fl_end; - } else { - end = stm->dev->fl_end; - num_pages = flash_addr_to_page_ceil(end) - first_page; - } - - if (!first_page && end == stm->dev->fl_end) - num_pages = 0xff; /* mass erase */ - } - - if (rd) { - unsigned int max_len = port_opts.rx_frame_max; - - fprintf(diag, "Memory read\n"); - - perr = parser->open(p_st, filename, 1); - if (perr != PARSER_ERR_OK) { - fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr)); - if (perr == PARSER_ERR_SYSTEM) - perror(filename); - goto close; - } - - fflush(diag); - addr = start; - while(addr < end) { - uint32_t left = end - addr; - len = max_len > left ? left : max_len; - s_err = stm32_read_memory(stm, addr, buffer, len); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to read memory at address 0x%08x, target write-protected?\n", addr); - goto close; - } - if (parser->write(p_st, buffer, len) != PARSER_ERR_OK) - { - fprintf(stderr, "Failed to write data to file\n"); - goto close; - } - addr += len; - - fprintf(diag, - "\rRead address 0x%08x (%.2f%%) ", - addr, - (100.0f / (float)(end - start)) * (float)(addr - start) - ); - fflush(diag); - } - fprintf(diag, "Done.\n"); - ret = 0; - goto close; - } else if (rp) { - fprintf(stdout, "Read-Protecting flash\n"); - /* the device automatically performs a reset after the sending the ACK */ - reset_flag = 0; - stm32_readprot_memory(stm); - fprintf(stdout, "Done.\n"); - } else if (ur) { - fprintf(stdout, "Read-UnProtecting flash\n"); - /* the device automatically performs a reset after the sending the ACK */ - reset_flag = 0; - stm32_runprot_memory(stm); - fprintf(stdout, "Done.\n"); - } else if (eraseOnly) { - ret = 0; - fprintf(stdout, "Erasing flash\n"); - - if (num_pages != 0xff && - (start != flash_page_to_addr(first_page) - || end != flash_page_to_addr(first_page + num_pages))) { - fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n"); - ret = 1; - goto close; - } - - s_err = stm32_erase_memory(stm, first_page, num_pages); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to erase memory\n"); - ret = 1; - goto close; - } - } else if (wu) { - fprintf(diag, "Write-unprotecting flash\n"); - /* the device automatically performs a reset after the sending the ACK */ - reset_flag = 0; - stm32_wunprot_memory(stm); - fprintf(diag, "Done.\n"); - - } else if (wr) { - fprintf(diag, "Write to memory\n"); - - off_t offset = 0; - ssize_t r; - unsigned int size; - unsigned int max_wlen, max_rlen; - - max_wlen = port_opts.tx_frame_max - 2; /* skip len and crc */ - max_wlen &= ~3; /* 32 bit aligned */ - - max_rlen = port_opts.rx_frame_max; - max_rlen = max_rlen < max_wlen ? max_rlen : max_wlen; - - /* Assume data from stdin is whole device */ - if (filename[0] == '-' && filename[1] == '\0') - size = end - start; - else - size = parser->size(p_st); - - // TODO: It is possible to write to non-page boundaries, by reading out flash - // from partial pages and combining with the input data - // if ((start % stm->dev->fl_ps) != 0 || (end % stm->dev->fl_ps) != 0) { - // fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n"); - // goto close; - // } - - // TODO: If writes are not page aligned, we should probably read out existing flash - // contents first, so it can be preserved and combined with new data - if (!no_erase && num_pages) { - fprintf(diag, "Erasing memory\n"); - s_err = stm32_erase_memory(stm, first_page, num_pages); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to erase memory\n"); - goto close; - } - } - - fflush(diag); - addr = start; - while(addr < end && offset < size) { - uint32_t left = end - addr; - len = max_wlen > left ? left : max_wlen; - len = len > size - offset ? size - offset : len; - - if (parser->read(p_st, buffer, &len) != PARSER_ERR_OK) - goto close; - - if (len == 0) { - if (filename[0] == '-') { - break; - } else { - fprintf(stderr, "Failed to read input file\n"); - goto close; - } - } - - again: - s_err = stm32_write_memory(stm, addr, buffer, len); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to write memory at address 0x%08x\n", addr); - goto close; - } - - if (verify) { - uint8_t compare[len]; - unsigned int offset, rlen; - - offset = 0; - while (offset < len) { - rlen = len - offset; - rlen = rlen < max_rlen ? rlen : max_rlen; - s_err = stm32_read_memory(stm, addr + offset, compare + offset, rlen); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to read memory at address 0x%08x\n", addr + offset); - goto close; - } - offset += rlen; - } - - for(r = 0; r < len; ++r) - if (buffer[r] != compare[r]) { - if (failed == retry) { - fprintf(stderr, "Failed to verify at address 0x%08x, expected 0x%02x and found 0x%02x\n", - (uint32_t)(addr + r), - buffer [r], - compare[r] - ); - goto close; - } - ++failed; - goto again; - } - - failed = 0; - } - - addr += len; - offset += len; - - fprintf(diag, - "\rWrote %saddress 0x%08x (%.2f%%) ", - verify ? "and verified " : "", - addr, - (100.0f / size) * offset - ); - fflush(diag); - - } - - fprintf(diag, "Done.\n"); - ret = 0; - goto close; - } else if (crc) { - uint32_t crc_val = 0; - - fprintf(diag, "CRC computation\n"); - - s_err = stm32_crc_wrapper(stm, start, end - start, &crc_val); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to read CRC\n"); - goto close; - } - fprintf(diag, "CRC(0x%08x-0x%08x) = 0x%08x\n", start, end, - crc_val); - ret = 0; - goto close; - } else - ret = 0; - -close: - if (stm && exec_flag && ret == 0) { - if (execute == 0) - execute = stm->dev->fl_start; - - fprintf(diag, "\nStarting execution at address 0x%08x... ", execute); - fflush(diag); - if (stm32_go(stm, execute) == STM32_ERR_OK) { - reset_flag = 0; - fprintf(diag, "done.\n"); - } else - fprintf(diag, "failed.\n"); - } - - if (stm && reset_flag) { - fprintf(diag, "\nResetting device... "); - fflush(diag); - if (init_bl_exit(stm, port, gpio_seq)) - fprintf(diag, "done.\n"); - else fprintf(diag, "failed.\n"); - } - - if (p_st ) parser->close(p_st); - if (stm ) stm32_close (stm); - if (port) - port->close(port); - - fprintf(diag, "\n"); - return ret; -} - -int parse_options(int argc, char *argv[]) -{ - int c; - char *pLen; - - while ((c = getopt(argc, argv, "a:b:m:r:w:e:vn:g:jkfcChuos:S:F:i:R")) != -1) { - switch(c) { - case 'a': - port_opts.bus_addr = strtoul(optarg, NULL, 0); - break; - - case 'b': - port_opts.baudRate = serial_get_baud(strtoul(optarg, NULL, 0)); - if (port_opts.baudRate == SERIAL_BAUD_INVALID) { - serial_baud_t baudrate; - fprintf(stderr, "Invalid baud rate, valid options are:\n"); - for (baudrate = SERIAL_BAUD_1200; baudrate != SERIAL_BAUD_INVALID; ++baudrate) - fprintf(stderr, " %d\n", serial_get_baud_int(baudrate)); - return 1; - } - break; - - case 'm': - if (strlen(optarg) != 3 - || serial_get_bits(optarg) == SERIAL_BITS_INVALID - || serial_get_parity(optarg) == SERIAL_PARITY_INVALID - || serial_get_stopbit(optarg) == SERIAL_STOPBIT_INVALID) { - fprintf(stderr, "Invalid serial mode\n"); - return 1; - } - port_opts.serial_mode = optarg; - break; - - case 'r': - case 'w': - rd = rd || c == 'r'; - wr = wr || c == 'w'; - if (rd && wr) { - fprintf(stderr, "ERROR: Invalid options, can't read & write at the same time\n"); - return 1; - } - filename = optarg; - if (filename[0] == '-') { - force_binary = 1; - } - break; - case 'e': - if (readwrite_len || start_addr) { - fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n"); - return 1; - } - npages = strtoul(optarg, NULL, 0); - if (npages > 0xFF || npages < 0) { - fprintf(stderr, "ERROR: You need to specify a page count between 0 and 255"); - return 1; - } - if (!npages) - no_erase = 1; - break; - case 'u': - wu = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't write unprotect and read/write at the same time\n"); - return 1; - } - break; - - case 'j': - rp = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't read protect and read/write at the same time\n"); - return 1; - } - break; - - case 'k': - ur = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't read unprotect and read/write at the same time\n"); - return 1; - } - break; - - case 'o': - eraseOnly = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't erase-only and read/write at the same time\n"); - return 1; - } - break; - - case 'v': - verify = 1; - break; - - case 'n': - retry = strtoul(optarg, NULL, 0); - break; - - case 'g': - exec_flag = 1; - execute = strtoul(optarg, NULL, 0); - if (execute % 4 != 0) { - fprintf(stderr, "ERROR: Execution address must be word-aligned\n"); - return 1; - } - break; - case 's': - if (readwrite_len || start_addr) { - fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n"); - return 1; - } - spage = strtoul(optarg, NULL, 0); - break; - case 'S': - if (spage || npages) { - fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n"); - return 1; - } else { - start_addr = strtoul(optarg, &pLen, 0); - if (*pLen == ':') { - pLen++; - readwrite_len = strtoul(pLen, NULL, 0); - if (readwrite_len == 0) { - fprintf(stderr, "ERROR: Invalid options, can't specify zero length\n"); - return 1; - } - } - } - break; - case 'F': - port_opts.rx_frame_max = strtoul(optarg, &pLen, 0); - if (*pLen == ':') { - pLen++; - port_opts.tx_frame_max = strtoul(pLen, NULL, 0); - } - if (port_opts.rx_frame_max < 0 - || port_opts.tx_frame_max < 0) { - fprintf(stderr, "ERROR: Invalid negative value for option -F\n"); - return 1; - } - if (port_opts.rx_frame_max == 0) - port_opts.rx_frame_max = STM32_MAX_RX_FRAME; - if (port_opts.tx_frame_max == 0) - port_opts.tx_frame_max = STM32_MAX_TX_FRAME; - if (port_opts.rx_frame_max < 20 - || port_opts.tx_frame_max < 5) { - fprintf(stderr, "ERROR: current code cannot work with small frames.\n"); - fprintf(stderr, "min(RX) = 20, min(TX) = 5\n"); - return 1; - } - if (port_opts.rx_frame_max > STM32_MAX_RX_FRAME) { - fprintf(stderr, "WARNING: Ignore RX length in option -F\n"); - port_opts.rx_frame_max = STM32_MAX_RX_FRAME; - } - if (port_opts.tx_frame_max > STM32_MAX_TX_FRAME) { - fprintf(stderr, "WARNING: Ignore TX length in option -F\n"); - port_opts.tx_frame_max = STM32_MAX_TX_FRAME; - } - break; - case 'f': - force_binary = 1; - break; - - case 'c': - init_flag = 0; - break; - - case 'h': - show_help(argv[0]); - exit(0); - - case 'i': - gpio_seq = optarg; - break; - - case 'R': - reset_flag = 1; - break; - - case 'C': - crc = 1; - break; - } - } - - for (c = optind; c < argc; ++c) { - if (port_opts.device) { - fprintf(stderr, "ERROR: Invalid parameter specified\n"); - show_help(argv[0]); - return 1; - } - port_opts.device = argv[c]; - } - - if (port_opts.device == NULL) { - fprintf(stderr, "ERROR: Device not specified\n"); - show_help(argv[0]); - return 1; - } - - if (!wr && verify) { - fprintf(stderr, "ERROR: Invalid usage, -v is only valid when writing\n"); - show_help(argv[0]); - return 1; - } - - return 0; -} - -void show_help(char *name) { - fprintf(stderr, - "Usage: %s [-bvngfhc] [-[rw] filename] [tty_device | i2c_device]\n" - " -a bus_address Bus address (e.g. for I2C port)\n" - " -b rate Baud rate (default 57600)\n" - " -m mode Serial port mode (default 8e1)\n" - " -r filename Read flash to file (or - stdout)\n" - " -w filename Write flash from file (or - stdout)\n" - " -C Compute CRC of flash content\n" - " -u Disable the flash write-protection\n" - " -j Enable the flash read-protection\n" - " -k Disable the flash read-protection\n" - " -o Erase only\n" - " -e n Only erase n pages before writing the flash\n" - " -v Verify writes\n" - " -n count Retry failed writes up to count times (default 10)\n" - " -g address Start execution at specified address (0 = flash start)\n" - " -S address[:length] Specify start address and optionally length for\n" - " read/write/erase operations\n" - " -F RX_length[:TX_length] Specify the max length of RX and TX frame\n" - " -s start_page Flash at specified page (0 = flash start)\n" - " -f Force binary parser\n" - " -h Show this help\n" - " -c Resume the connection (don't send initial INIT)\n" - " *Baud rate must be kept the same as the first init*\n" - " This is useful if the reset fails\n" - " -i GPIO_string GPIO sequence to enter/exit bootloader mode\n" - " GPIO_string=[entry_seq][:[exit_seq]]\n" - " sequence=[-]n[,sequence]\n" - " -R Reset device at exit.\n" - "\n" - "Examples:\n" - " Get device information:\n" - " %s /dev/ttyS0\n" - " or:\n" - " %s /dev/i2c-0\n" - "\n" - " Write with verify and then start execution:\n" - " %s -w filename -v -g 0x0 /dev/ttyS0\n" - "\n" - " Read flash to file:\n" - " %s -r filename /dev/ttyS0\n" - "\n" - " Read 100 bytes of flash from 0x1000 to stdout:\n" - " %s -r - -S 0x1000:100 /dev/ttyS0\n" - "\n" - " Start execution:\n" - " %s -g 0x0 /dev/ttyS0\n" - "\n" - " GPIO sequence:\n" - " - entry sequence: GPIO_3=low, GPIO_2=low, GPIO_2=high\n" - " - exit sequence: GPIO_3=high, GPIO_2=low, GPIO_2=high\n" - " %s -i -3,-2,2:3,-2,2 /dev/ttyS0\n", - name, - name, - name, - name, - name, - name, - name, - name - ); -} - diff --git a/linux64/src/stm32flash_serial/src/parsers/Android.mk b/linux64/src/stm32flash_serial/src/parsers/Android.mk deleted file mode 100644 index afec18cd5..000000000 --- a/linux64/src/stm32flash_serial/src/parsers/Android.mk +++ /dev/null @@ -1,6 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := libparsers -LOCAL_SRC_FILES := binary.c hex.c -include $(BUILD_STATIC_LIBRARY) diff --git a/linux64/src/stm32flash_serial/src/parsers/Makefile b/linux64/src/stm32flash_serial/src/parsers/Makefile deleted file mode 100644 index bb7df1e02..000000000 --- a/linux64/src/stm32flash_serial/src/parsers/Makefile +++ /dev/null @@ -1,12 +0,0 @@ - -CFLAGS += -Wall -g - -all: parsers.a - -parsers.a: binary.o hex.o - $(AR) rc $@ binary.o hex.o - -clean: - rm -f *.o parsers.a - -.PHONY: all clean diff --git a/linux64/src/stm32flash_serial/src/parsers/binary.c b/linux64/src/stm32flash_serial/src/parsers/binary.c deleted file mode 100644 index f491952bb..000000000 --- a/linux64/src/stm32flash_serial/src/parsers/binary.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include - -#include "binary.h" - -typedef struct { - int fd; - char write; - struct stat stat; -} binary_t; - -void* binary_init() { - return calloc(sizeof(binary_t), 1); -} - -parser_err_t binary_open(void *storage, const char *filename, const char write) { - binary_t *st = storage; - if (write) { - if (filename[0] == '-') - st->fd = 1; - else - st->fd = open( - filename, -#ifndef __WIN32__ - O_WRONLY | O_CREAT | O_TRUNC, -#else - O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, -#endif -#ifndef __WIN32__ - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH -#else - 0 -#endif - ); - st->stat.st_size = 0; - } else { - if (filename[0] == '-') { - st->fd = 0; - } else { - if (stat(filename, &st->stat) != 0) - return PARSER_ERR_INVALID_FILE; - st->fd = open(filename, -#ifndef __WIN32__ - O_RDONLY -#else - O_RDONLY | O_BINARY -#endif - ); - } - } - - st->write = write; - return st->fd == -1 ? PARSER_ERR_SYSTEM : PARSER_ERR_OK; -} - -parser_err_t binary_close(void *storage) { - binary_t *st = storage; - - if (st->fd) close(st->fd); - free(st); - return PARSER_ERR_OK; -} - -unsigned int binary_size(void *storage) { - binary_t *st = storage; - return st->stat.st_size; -} - -parser_err_t binary_read(void *storage, void *data, unsigned int *len) { - binary_t *st = storage; - unsigned int left = *len; - if (st->write) return PARSER_ERR_WRONLY; - - ssize_t r; - while(left > 0) { - r = read(st->fd, data, left); - /* If there is no data to read at all, return OK, but with zero read */ - if (r == 0 && left == *len) { - *len = 0; - return PARSER_ERR_OK; - } - if (r <= 0) return PARSER_ERR_SYSTEM; - left -= r; - data += r; - } - - *len = *len - left; - return PARSER_ERR_OK; -} - -parser_err_t binary_write(void *storage, void *data, unsigned int len) { - binary_t *st = storage; - if (!st->write) return PARSER_ERR_RDONLY; - - ssize_t r; - while(len > 0) { - r = write(st->fd, data, len); - if (r < 1) return PARSER_ERR_SYSTEM; - st->stat.st_size += r; - - len -= r; - data += r; - } - - return PARSER_ERR_OK; -} - -parser_t PARSER_BINARY = { - "Raw BINARY", - binary_init, - binary_open, - binary_close, - binary_size, - binary_read, - binary_write -}; - diff --git a/linux64/src/stm32flash_serial/src/parsers/binary.h b/linux64/src/stm32flash_serial/src/parsers/binary.h deleted file mode 100644 index d989acfa0..000000000 --- a/linux64/src/stm32flash_serial/src/parsers/binary.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _PARSER_BINARY_H -#define _PARSER_BINARY_H - -#include "parser.h" - -extern parser_t PARSER_BINARY; -#endif diff --git a/linux64/src/stm32flash_serial/src/parsers/hex.c b/linux64/src/stm32flash_serial/src/parsers/hex.c deleted file mode 100644 index 3baf85623..000000000 --- a/linux64/src/stm32flash_serial/src/parsers/hex.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include - -#include "hex.h" -#include "../utils.h" - -typedef struct { - size_t data_len, offset; - uint8_t *data; - uint8_t base; -} hex_t; - -void* hex_init() { - return calloc(sizeof(hex_t), 1); -} - -parser_err_t hex_open(void *storage, const char *filename, const char write) { - hex_t *st = storage; - if (write) { - return PARSER_ERR_RDONLY; - } else { - char mark; - int i, fd; - uint8_t checksum; - unsigned int c; - uint32_t base = 0; - unsigned int last_address = 0x0; - - fd = open(filename, O_RDONLY); - if (fd < 0) - return PARSER_ERR_SYSTEM; - - /* read in the file */ - - while(read(fd, &mark, 1) != 0) { - if (mark == '\n' || mark == '\r') continue; - if (mark != ':') - return PARSER_ERR_INVALID_FILE; - - char buffer[9]; - unsigned int reclen, address, type; - uint8_t *record = NULL; - - /* get the reclen, address, and type */ - buffer[8] = 0; - if (read(fd, &buffer, 8) != 8) return PARSER_ERR_INVALID_FILE; - if (sscanf(buffer, "%2x%4x%2x", &reclen, &address, &type) != 3) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - /* setup the checksum */ - checksum = - reclen + - ((address & 0xFF00) >> 8) + - ((address & 0x00FF) >> 0) + - type; - - switch(type) { - /* data record */ - case 0: - c = address - last_address; - st->data = realloc(st->data, st->data_len + c + reclen); - - /* if there is a gap, set it to 0xff and increment the length */ - if (c > 0) { - memset(&st->data[st->data_len], 0xff, c); - st->data_len += c; - } - - last_address = address + reclen; - record = &st->data[st->data_len]; - st->data_len += reclen; - break; - - /* extended segment address record */ - case 2: - base = 0; - break; - - /* extended linear address record */ - case 4: - base = address; - break; - } - - buffer[2] = 0; - for(i = 0; i < reclen; ++i) { - if (read(fd, &buffer, 2) != 2 || sscanf(buffer, "%2x", &c) != 1) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - /* add the byte to the checksum */ - checksum += c; - - switch(type) { - case 0: - if (record != NULL) { - record[i] = c; - } else { - return PARSER_ERR_INVALID_FILE; - } - break; - - case 2: - case 4: - base = (base << 8) | c; - break; - } - } - - /* read, scan, and verify the checksum */ - if ( - read(fd, &buffer, 2 ) != 2 || - sscanf(buffer, "%2x", &c) != 1 || - (uint8_t)(checksum + c) != 0x00 - ) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - switch(type) { - /* EOF */ - case 1: - close(fd); - return PARSER_ERR_OK; - - /* address record */ - case 2: base = base << 4; - case 4: base = be_u32(base); - /* Reset last_address since our base changed */ - last_address = 0; - - if (st->base == 0) { - st->base = base; - break; - } - - /* we cant cope with files out of order */ - if (base < st->base) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - /* if there is a gap, enlarge and fill with zeros */ - unsigned int len = base - st->base; - if (len > st->data_len) { - st->data = realloc(st->data, len); - memset(&st->data[st->data_len], 0, len - st->data_len); - st->data_len = len; - } - break; - } - } - - close(fd); - return PARSER_ERR_OK; - } -} - -parser_err_t hex_close(void *storage) { - hex_t *st = storage; - if (st) free(st->data); - free(st); - return PARSER_ERR_OK; -} - -unsigned int hex_size(void *storage) { - hex_t *st = storage; - return st->data_len; -} - -parser_err_t hex_read(void *storage, void *data, unsigned int *len) { - hex_t *st = storage; - unsigned int left = st->data_len - st->offset; - unsigned int get = left > *len ? *len : left; - - memcpy(data, &st->data[st->offset], get); - st->offset += get; - - *len = get; - return PARSER_ERR_OK; -} - -parser_err_t hex_write(void *storage, void *data, unsigned int len) { - return PARSER_ERR_RDONLY; -} - -parser_t PARSER_HEX = { - "Intel HEX", - hex_init, - hex_open, - hex_close, - hex_size, - hex_read, - hex_write -}; - diff --git a/linux64/src/stm32flash_serial/src/parsers/hex.h b/linux64/src/stm32flash_serial/src/parsers/hex.h deleted file mode 100644 index 02413c9c9..000000000 --- a/linux64/src/stm32flash_serial/src/parsers/hex.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _PARSER_HEX_H -#define _PARSER_HEX_H - -#include "parser.h" - -extern parser_t PARSER_HEX; -#endif diff --git a/linux64/src/stm32flash_serial/src/parsers/parser.h b/linux64/src/stm32flash_serial/src/parsers/parser.h deleted file mode 100644 index c2fae3cf8..000000000 --- a/linux64/src/stm32flash_serial/src/parsers/parser.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _H_PARSER -#define _H_PARSER - -enum parser_err { - PARSER_ERR_OK, - PARSER_ERR_SYSTEM, - PARSER_ERR_INVALID_FILE, - PARSER_ERR_WRONLY, - PARSER_ERR_RDONLY -}; -typedef enum parser_err parser_err_t; - -struct parser { - const char *name; - void* (*init )(); /* initialise the parser */ - parser_err_t (*open )(void *storage, const char *filename, const char write); /* open the file for read|write */ - parser_err_t (*close)(void *storage); /* close and free the parser */ - unsigned int (*size )(void *storage); /* get the total data size */ - parser_err_t (*read )(void *storage, void *data, unsigned int *len); /* read a block of data */ - parser_err_t (*write)(void *storage, void *data, unsigned int len); /* write a block of data */ -}; -typedef struct parser parser_t; - -static inline const char* parser_errstr(parser_err_t err) { - switch(err) { - case PARSER_ERR_OK : return "OK"; - case PARSER_ERR_SYSTEM : return "System Error"; - case PARSER_ERR_INVALID_FILE: return "Invalid File"; - case PARSER_ERR_WRONLY : return "Parser can only write"; - case PARSER_ERR_RDONLY : return "Parser can only read"; - default: - return "Unknown Error"; - } -} - -#endif diff --git a/linux64/src/stm32flash_serial/src/port.c b/linux64/src/stm32flash_serial/src/port.c deleted file mode 100644 index 08e58cc34..000000000 --- a/linux64/src/stm32flash_serial/src/port.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include - -#include "serial.h" -#include "port.h" - - -extern struct port_interface port_serial; -extern struct port_interface port_i2c; - -static struct port_interface *ports[] = { - &port_serial, - &port_i2c, - NULL, -}; - - -port_err_t port_open(struct port_options *ops, struct port_interface **outport) -{ - int ret; - static struct port_interface **port; - - for (port = ports; *port; port++) { - ret = (*port)->open(*port, ops); - if (ret == PORT_ERR_NODEV) - continue; - if (ret == PORT_ERR_OK) - break; - fprintf(stderr, "Error probing interface \"%s\"\n", - (*port)->name); - } - if (*port == NULL) { - fprintf(stderr, "Cannot handle device \"%s\"\n", - ops->device); - return PORT_ERR_UNKNOWN; - } - - *outport = *port; - return PORT_ERR_OK; -} diff --git a/linux64/src/stm32flash_serial/src/port.h b/linux64/src/stm32flash_serial/src/port.h deleted file mode 100644 index 290f03496..000000000 --- a/linux64/src/stm32flash_serial/src/port.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _H_PORT -#define _H_PORT - -typedef enum { - PORT_ERR_OK = 0, - PORT_ERR_NODEV, /* No such device */ - PORT_ERR_TIMEDOUT, /* Operation timed out */ - PORT_ERR_UNKNOWN, -} port_err_t; - -/* flags */ -#define PORT_BYTE (1 << 0) /* byte (not frame) oriented */ -#define PORT_GVR_ETX (1 << 1) /* cmd GVR returns protection status */ -#define PORT_CMD_INIT (1 << 2) /* use INIT cmd to autodetect speed */ -#define PORT_RETRY (1 << 3) /* allowed read() retry after timeout */ -#define PORT_STRETCH_W (1 << 4) /* warning for no-stretching commands */ - -/* all options and flags used to open and configure an interface */ -struct port_options { - const char *device; - serial_baud_t baudRate; - const char *serial_mode; - int bus_addr; - int rx_frame_max; - int tx_frame_max; -}; - -/* - * Specify the length of reply for command GET - * This is helpful for frame-oriented protocols, e.g. i2c, to avoid time - * consuming try-fail-timeout-retry operation. - * On byte-oriented protocols, i.e. UART, this information would be skipped - * after read the first byte, so not needed. - */ -struct varlen_cmd { - uint8_t version; - uint8_t length; -}; - -struct port_interface { - const char *name; - unsigned flags; - port_err_t (*open)(struct port_interface *port, struct port_options *ops); - port_err_t (*close)(struct port_interface *port); - port_err_t (*read)(struct port_interface *port, void *buf, size_t nbyte); - port_err_t (*write)(struct port_interface *port, void *buf, size_t nbyte); - port_err_t (*gpio)(struct port_interface *port, serial_gpio_t n, int level); - const char *(*get_cfg_str)(struct port_interface *port); - struct varlen_cmd *cmd_get_reply; - void *private; -}; - -port_err_t port_open(struct port_options *ops, struct port_interface **outport); - -#endif diff --git a/linux64/src/stm32flash_serial/src/protocol.txt b/linux64/src/stm32flash_serial/src/protocol.txt deleted file mode 100644 index 039109908..000000000 --- a/linux64/src/stm32flash_serial/src/protocol.txt +++ /dev/null @@ -1,19 +0,0 @@ -The communication protocol used by ST bootloader is documented in following ST -application notes, depending on communication port. - -In current version of stm32flash are supported only UART and I2C ports. - -* AN3154: CAN protocol used in the STM32 bootloader - http://www.st.com/web/en/resource/technical/document/application_note/CD00264321.pdf - -* AN3155: USART protocol used in the STM32(TM) bootloader - http://www.st.com/web/en/resource/technical/document/application_note/CD00264342.pdf - -* AN4221: I2C protocol used in the STM32 bootloader - http://www.st.com/web/en/resource/technical/document/application_note/DM00072315.pdf - -* AN4286: SPI protocol used in the STM32 bootloader - http://www.st.com/web/en/resource/technical/document/application_note/DM00081379.pdf - -Boot mode selection for STM32 is documented in ST application note AN2606, available in ST website: - http://www.st.com/web/en/resource/technical/document/application_note/CD00167594.pdf diff --git a/linux64/src/stm32flash_serial/src/serial.h b/linux64/src/stm32flash_serial/src/serial.h deleted file mode 100644 index 227ba163b..000000000 --- a/linux64/src/stm32flash_serial/src/serial.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _SERIAL_H -#define _SERIAL_H - -typedef struct serial serial_t; - -typedef enum { - SERIAL_PARITY_NONE, - SERIAL_PARITY_EVEN, - SERIAL_PARITY_ODD, - - SERIAL_PARITY_INVALID -} serial_parity_t; - -typedef enum { - SERIAL_BITS_5, - SERIAL_BITS_6, - SERIAL_BITS_7, - SERIAL_BITS_8, - - SERIAL_BITS_INVALID -} serial_bits_t; - -typedef enum { - SERIAL_BAUD_1200, - SERIAL_BAUD_1800, - SERIAL_BAUD_2400, - SERIAL_BAUD_4800, - SERIAL_BAUD_9600, - SERIAL_BAUD_19200, - SERIAL_BAUD_38400, - SERIAL_BAUD_57600, - SERIAL_BAUD_115200, - SERIAL_BAUD_128000, - SERIAL_BAUD_230400, - SERIAL_BAUD_256000, - SERIAL_BAUD_460800, - SERIAL_BAUD_500000, - SERIAL_BAUD_576000, - SERIAL_BAUD_921600, - SERIAL_BAUD_1000000, - SERIAL_BAUD_1500000, - SERIAL_BAUD_2000000, - - SERIAL_BAUD_INVALID -} serial_baud_t; - -typedef enum { - SERIAL_STOPBIT_1, - SERIAL_STOPBIT_2, - - SERIAL_STOPBIT_INVALID -} serial_stopbit_t; - -typedef enum { - GPIO_RTS = 1, - GPIO_DTR, - GPIO_BRK, -} serial_gpio_t; - -/* common helper functions */ -serial_baud_t serial_get_baud(const unsigned int baud); -unsigned int serial_get_baud_int(const serial_baud_t baud); -serial_bits_t serial_get_bits(const char *mode); -unsigned int serial_get_bits_int(const serial_bits_t bits); -serial_parity_t serial_get_parity(const char *mode); -char serial_get_parity_str(const serial_parity_t parity); -serial_stopbit_t serial_get_stopbit(const char *mode); -unsigned int serial_get_stopbit_int(const serial_stopbit_t stopbit); - -#endif diff --git a/linux64/src/stm32flash_serial/src/serial_common.c b/linux64/src/stm32flash_serial/src/serial_common.c deleted file mode 100644 index 43e48e1ac..000000000 --- a/linux64/src/stm32flash_serial/src/serial_common.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "serial.h" - -serial_baud_t serial_get_baud(const unsigned int baud) { - switch(baud) { - case 1200: return SERIAL_BAUD_1200 ; - case 1800: return SERIAL_BAUD_1800 ; - case 2400: return SERIAL_BAUD_2400 ; - case 4800: return SERIAL_BAUD_4800 ; - case 9600: return SERIAL_BAUD_9600 ; - case 19200: return SERIAL_BAUD_19200 ; - case 38400: return SERIAL_BAUD_38400 ; - case 57600: return SERIAL_BAUD_57600 ; - case 115200: return SERIAL_BAUD_115200; - case 128000: return SERIAL_BAUD_128000; - case 230400: return SERIAL_BAUD_230400; - case 256000: return SERIAL_BAUD_256000; - case 460800: return SERIAL_BAUD_460800; - case 500000: return SERIAL_BAUD_500000; - case 576000: return SERIAL_BAUD_576000; - case 921600: return SERIAL_BAUD_921600; - case 1000000: return SERIAL_BAUD_1000000; - case 1500000: return SERIAL_BAUD_1500000; - case 2000000: return SERIAL_BAUD_2000000; - - default: - return SERIAL_BAUD_INVALID; - } -} - -unsigned int serial_get_baud_int(const serial_baud_t baud) { - switch(baud) { - case SERIAL_BAUD_1200 : return 1200 ; - case SERIAL_BAUD_1800 : return 1800 ; - case SERIAL_BAUD_2400 : return 2400 ; - case SERIAL_BAUD_4800 : return 4800 ; - case SERIAL_BAUD_9600 : return 9600 ; - case SERIAL_BAUD_19200 : return 19200 ; - case SERIAL_BAUD_38400 : return 38400 ; - case SERIAL_BAUD_57600 : return 57600 ; - case SERIAL_BAUD_115200: return 115200; - case SERIAL_BAUD_128000: return 128000; - case SERIAL_BAUD_230400: return 230400; - case SERIAL_BAUD_256000: return 256000; - case SERIAL_BAUD_460800: return 460800; - case SERIAL_BAUD_500000: return 500000; - case SERIAL_BAUD_576000: return 576000; - case SERIAL_BAUD_921600: return 921600; - case SERIAL_BAUD_1000000: return 1000000; - case SERIAL_BAUD_1500000: return 1500000; - case SERIAL_BAUD_2000000: return 2000000; - - case SERIAL_BAUD_INVALID: - default: - return 0; - } -} - -serial_bits_t serial_get_bits(const char *mode) { - if (!mode) - return SERIAL_BITS_INVALID; - switch(mode[0]) { - case '5': return SERIAL_BITS_5; - case '6': return SERIAL_BITS_6; - case '7': return SERIAL_BITS_7; - case '8': return SERIAL_BITS_8; - - default: - return SERIAL_BITS_INVALID; - } -} - -unsigned int serial_get_bits_int(const serial_bits_t bits) { - switch(bits) { - case SERIAL_BITS_5: return 5; - case SERIAL_BITS_6: return 6; - case SERIAL_BITS_7: return 7; - case SERIAL_BITS_8: return 8; - - default: - return 0; - } -} - -serial_parity_t serial_get_parity(const char *mode) { - if (!mode || !mode[0]) - return SERIAL_PARITY_INVALID; - switch(mode[1]) { - case 'N': - case 'n': - return SERIAL_PARITY_NONE; - case 'E': - case 'e': - return SERIAL_PARITY_EVEN; - case 'O': - case 'o': - return SERIAL_PARITY_ODD; - - default: - return SERIAL_PARITY_INVALID; - } -} - -char serial_get_parity_str(const serial_parity_t parity) { - switch(parity) { - case SERIAL_PARITY_NONE: return 'N'; - case SERIAL_PARITY_EVEN: return 'E'; - case SERIAL_PARITY_ODD : return 'O'; - - default: - return ' '; - } -} - -serial_stopbit_t serial_get_stopbit(const char *mode) { - if (!mode || !mode[0] || !mode[1]) - return SERIAL_STOPBIT_INVALID; - switch(mode[2]) { - case '1': return SERIAL_STOPBIT_1; - case '2': return SERIAL_STOPBIT_2; - - default: - return SERIAL_STOPBIT_INVALID; - } -} - -unsigned int serial_get_stopbit_int(const serial_stopbit_t stopbit) { - switch(stopbit) { - case SERIAL_STOPBIT_1: return 1; - case SERIAL_STOPBIT_2: return 2; - - default: - return 0; - } -} - diff --git a/linux64/src/stm32flash_serial/src/serial_platform.c b/linux64/src/stm32flash_serial/src/serial_platform.c deleted file mode 100644 index 98e256921..000000000 --- a/linux64/src/stm32flash_serial/src/serial_platform.c +++ /dev/null @@ -1,5 +0,0 @@ -#if defined(__WIN32__) || defined(__CYGWIN__) -# include "serial_w32.c" -#else -# include "serial_posix.c" -#endif diff --git a/linux64/src/stm32flash_serial/src/serial_posix.c b/linux64/src/stm32flash_serial/src/serial_posix.c deleted file mode 100644 index 284b35b20..000000000 --- a/linux64/src/stm32flash_serial/src/serial_posix.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "serial.h" -#include "port.h" - -struct serial { - int fd; - struct termios oldtio; - struct termios newtio; - char setup_str[11]; -}; - -static serial_t *serial_open(const char *device) -{ - serial_t *h = calloc(sizeof(serial_t), 1); - - h->fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); - if (h->fd < 0) { - free(h); - return NULL; - } - fcntl(h->fd, F_SETFL, 0); - - tcgetattr(h->fd, &h->oldtio); - tcgetattr(h->fd, &h->newtio); - - return h; -} - -static void serial_flush(const serial_t *h) -{ - tcflush(h->fd, TCIFLUSH); -} - -static void serial_close(serial_t *h) -{ - serial_flush(h); - tcsetattr(h->fd, TCSANOW, &h->oldtio); - close(h->fd); - free(h); -} - -static port_err_t serial_setup(serial_t *h, const serial_baud_t baud, - const serial_bits_t bits, - const serial_parity_t parity, - const serial_stopbit_t stopbit) -{ - speed_t port_baud; - tcflag_t port_bits; - tcflag_t port_parity; - tcflag_t port_stop; - struct termios settings; - - switch (baud) { - case SERIAL_BAUD_1200: port_baud = B1200; break; - case SERIAL_BAUD_1800: port_baud = B1800; break; - case SERIAL_BAUD_2400: port_baud = B2400; break; - case SERIAL_BAUD_4800: port_baud = B4800; break; - case SERIAL_BAUD_9600: port_baud = B9600; break; - case SERIAL_BAUD_19200: port_baud = B19200; break; - case SERIAL_BAUD_38400: port_baud = B38400; break; - case SERIAL_BAUD_57600: port_baud = B57600; break; - case SERIAL_BAUD_115200: port_baud = B115200; break; - case SERIAL_BAUD_230400: port_baud = B230400; break; -#ifdef B460800 - case SERIAL_BAUD_460800: port_baud = B460800; break; -#endif /* B460800 */ -#ifdef B921600 - case SERIAL_BAUD_921600: port_baud = B921600; break; -#endif /* B921600 */ -#ifdef B500000 - case SERIAL_BAUD_500000: port_baud = B500000; break; -#endif /* B500000 */ -#ifdef B576000 - case SERIAL_BAUD_576000: port_baud = B576000; break; -#endif /* B576000 */ -#ifdef B1000000 - case SERIAL_BAUD_1000000: port_baud = B1000000; break; -#endif /* B1000000 */ -#ifdef B1500000 - case SERIAL_BAUD_1500000: port_baud = B1500000; break; -#endif /* B1500000 */ -#ifdef B2000000 - case SERIAL_BAUD_2000000: port_baud = B2000000; break; -#endif /* B2000000 */ - - case SERIAL_BAUD_INVALID: - default: - return PORT_ERR_UNKNOWN; - } - - switch (bits) { - case SERIAL_BITS_5: port_bits = CS5; break; - case SERIAL_BITS_6: port_bits = CS6; break; - case SERIAL_BITS_7: port_bits = CS7; break; - case SERIAL_BITS_8: port_bits = CS8; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (parity) { - case SERIAL_PARITY_NONE: port_parity = 0; break; - case SERIAL_PARITY_EVEN: port_parity = PARENB; break; - case SERIAL_PARITY_ODD: port_parity = PARENB | PARODD; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (stopbit) { - case SERIAL_STOPBIT_1: port_stop = 0; break; - case SERIAL_STOPBIT_2: port_stop = CSTOPB; break; - - default: - return PORT_ERR_UNKNOWN; - } - - /* reset the settings */ -#ifndef __sun /* Used by GNU and BSD. Ignore __SVR4 in test. */ - cfmakeraw(&h->newtio); -#else /* __sun */ - h->newtio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR - | IGNCR | ICRNL | IXON); - if (port_parity) - h->newtio.c_iflag |= INPCK; - - h->newtio.c_oflag &= ~OPOST; - h->newtio.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - h->newtio.c_cflag &= ~(CSIZE | PARENB); - h->newtio.c_cflag |= CS8; -#endif /* __sun */ -#ifdef __QNXNTO__ - h->newtio.c_cflag &= ~(CSIZE | IHFLOW | OHFLOW); -#else - h->newtio.c_cflag &= ~(CSIZE | CRTSCTS); -#endif - h->newtio.c_cflag &= ~(CSIZE | CRTSCTS); - h->newtio.c_iflag &= ~(IXON | IXOFF | IXANY | IGNPAR); - h->newtio.c_lflag &= ~(ECHOK | ECHOCTL | ECHOKE); - h->newtio.c_oflag &= ~(OPOST | ONLCR); - - /* setup the new settings */ - cfsetispeed(&h->newtio, port_baud); - cfsetospeed(&h->newtio, port_baud); - h->newtio.c_cflag |= - port_parity | - port_bits | - port_stop | - CLOCAL | - CREAD; - - h->newtio.c_cc[VMIN] = 0; - h->newtio.c_cc[VTIME] = 5; /* in units of 0.1 s */ - - /* set the settings */ - serial_flush(h); - if (tcsetattr(h->fd, TCSANOW, &h->newtio) != 0) - return PORT_ERR_UNKNOWN; - -/* this check fails on CDC-ACM devices, bits 16 and 17 of cflag differ! - * it has been disabled below for now -jcw, 2015-11-09 - if (settings.c_cflag != h->newtio.c_cflag) - fprintf(stderr, "c_cflag mismatch %lx\n", - settings.c_cflag ^ h->newtio.c_cflag); - */ - - /* confirm they were set */ - tcgetattr(h->fd, &settings); - if (settings.c_iflag != h->newtio.c_iflag || - settings.c_oflag != h->newtio.c_oflag || - //settings.c_cflag != h->newtio.c_cflag || - settings.c_lflag != h->newtio.c_lflag) - return PORT_ERR_UNKNOWN; - - snprintf(h->setup_str, sizeof(h->setup_str), "%u %d%c%d", - serial_get_baud_int(baud), - serial_get_bits_int(bits), - serial_get_parity_str(parity), - serial_get_stopbit_int(stopbit)); - return PORT_ERR_OK; -} - -/* - * Roger clark. - * This function is no longer used. But has just been commented out in case it needs - * to be reinstated in the future - -static int startswith(const char *haystack, const char *needle) { - return strncmp(haystack, needle, strlen(needle)) == 0; -} -*/ - -static int is_tty(const char *path) { - char resolved[PATH_MAX]; - - if(!realpath(path, resolved)) return 0; - - - /* - * Roger Clark - * Commented out this check, because on OSX some devices are /dev/cu - * and some users use symbolic links to devices, hence the name may not even start - * with /dev - - if(startswith(resolved, "/dev/tty")) return 1; - - return 0; - */ - - return 1; -} - -static port_err_t serial_posix_open(struct port_interface *port, - struct port_options *ops) -{ - serial_t *h; - - /* 1. check device name match */ - if (!is_tty(ops->device)) - return PORT_ERR_NODEV; - - /* 2. check options */ - if (ops->baudRate == SERIAL_BAUD_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_bits(ops->serial_mode) == SERIAL_BITS_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_parity(ops->serial_mode) == SERIAL_PARITY_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_stopbit(ops->serial_mode) == SERIAL_STOPBIT_INVALID) - return PORT_ERR_UNKNOWN; - - /* 3. open it */ - h = serial_open(ops->device); - if (h == NULL) - return PORT_ERR_UNKNOWN; - - /* 4. set options */ - if (serial_setup(h, ops->baudRate, - serial_get_bits(ops->serial_mode), - serial_get_parity(ops->serial_mode), - serial_get_stopbit(ops->serial_mode) - ) != PORT_ERR_OK) { - serial_close(h); - return PORT_ERR_UNKNOWN; - } - - port->private = h; - return PORT_ERR_OK; -} - -static port_err_t serial_posix_close(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - serial_close(h); - port->private = NULL; - return PORT_ERR_OK; -} - -static port_err_t serial_posix_read(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - ssize_t r; - uint8_t *pos = (uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - r = read(h->fd, pos, nbyte); - if (r == 0) - return PORT_ERR_TIMEDOUT; - if (r < 0) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_posix_write(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - ssize_t r; - const uint8_t *pos = (const uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - r = write(h->fd, pos, nbyte); - if (r < 1) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_posix_gpio(struct port_interface *port, - serial_gpio_t n, int level) -{ - serial_t *h; - int bit, lines; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - switch (n) { - case GPIO_RTS: - bit = TIOCM_RTS; - break; - - case GPIO_DTR: - bit = TIOCM_DTR; - break; - - case GPIO_BRK: - if (level == 0) - return PORT_ERR_OK; - if (tcsendbreak(h->fd, 1)) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; - - default: - return PORT_ERR_UNKNOWN; - } - - /* handle RTS/DTR */ - if (ioctl(h->fd, TIOCMGET, &lines)) - return PORT_ERR_UNKNOWN; - lines = level ? lines | bit : lines & ~bit; - if (ioctl(h->fd, TIOCMSET, &lines)) - return PORT_ERR_UNKNOWN; - - return PORT_ERR_OK; -} - -static const char *serial_posix_get_cfg_str(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - return h ? h->setup_str : "INVALID"; -} - -struct port_interface port_serial = { - .name = "serial_posix", - .flags = PORT_BYTE | PORT_GVR_ETX | PORT_CMD_INIT | PORT_RETRY, - .open = serial_posix_open, - .close = serial_posix_close, - .read = serial_posix_read, - .write = serial_posix_write, - .gpio = serial_posix_gpio, - .get_cfg_str = serial_posix_get_cfg_str, -}; diff --git a/linux64/src/stm32flash_serial/src/serial_w32.c b/linux64/src/stm32flash_serial/src/serial_w32.c deleted file mode 100644 index 56772c0a0..000000000 --- a/linux64/src/stm32flash_serial/src/serial_w32.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2010 Gareth McMullin - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "serial.h" -#include "port.h" - -struct serial { - HANDLE fd; - DCB oldtio; - DCB newtio; - char setup_str[11]; -}; - -static serial_t *serial_open(const char *device) -{ - serial_t *h = calloc(sizeof(serial_t), 1); - char *devName; - - /* timeout in ms */ - COMMTIMEOUTS timeouts = {MAXDWORD, MAXDWORD, 500, 0, 0}; - - /* Fix the device name if required */ - if (strlen(device) > 4 && device[0] != '\\') { - devName = calloc(1, strlen(device) + 5); - sprintf(devName, "\\\\.\\%s", device); - } else { - devName = (char *)device; - } - - /* Create file handle for port */ - h->fd = CreateFile(devName, GENERIC_READ | GENERIC_WRITE, - 0, /* Exclusive access */ - NULL, /* No security */ - OPEN_EXISTING, - 0, /* No overlap */ - NULL); - - if (devName != device) - free(devName); - - if (h->fd == INVALID_HANDLE_VALUE) { - if (GetLastError() == ERROR_FILE_NOT_FOUND) - fprintf(stderr, "File not found: %s\n", device); - return NULL; - } - - SetupComm(h->fd, 4096, 4096); /* Set input and output buffer size */ - - SetCommTimeouts(h->fd, &timeouts); - - SetCommMask(h->fd, EV_ERR); /* Notify us of error events */ - - GetCommState(h->fd, &h->oldtio); /* Retrieve port parameters */ - GetCommState(h->fd, &h->newtio); /* Retrieve port parameters */ - - /* PurgeComm(h->fd, PURGE_RXABORT | PURGE_TXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); */ - - return h; -} - -static void serial_flush(const serial_t *h) -{ - /* We shouldn't need to flush in non-overlapping (blocking) mode */ - /* tcflush(h->fd, TCIFLUSH); */ -} - -static void serial_close(serial_t *h) -{ - serial_flush(h); - SetCommState(h->fd, &h->oldtio); - CloseHandle(h->fd); - free(h); -} - -static port_err_t serial_setup(serial_t *h, - const serial_baud_t baud, - const serial_bits_t bits, - const serial_parity_t parity, - const serial_stopbit_t stopbit) -{ - switch (baud) { - case SERIAL_BAUD_1200: h->newtio.BaudRate = CBR_1200; break; - /* case SERIAL_BAUD_1800: h->newtio.BaudRate = CBR_1800; break; */ - case SERIAL_BAUD_2400: h->newtio.BaudRate = CBR_2400; break; - case SERIAL_BAUD_4800: h->newtio.BaudRate = CBR_4800; break; - case SERIAL_BAUD_9600: h->newtio.BaudRate = CBR_9600; break; - case SERIAL_BAUD_19200: h->newtio.BaudRate = CBR_19200; break; - case SERIAL_BAUD_38400: h->newtio.BaudRate = CBR_38400; break; - case SERIAL_BAUD_57600: h->newtio.BaudRate = CBR_57600; break; - case SERIAL_BAUD_115200: h->newtio.BaudRate = CBR_115200; break; - case SERIAL_BAUD_128000: h->newtio.BaudRate = CBR_128000; break; - case SERIAL_BAUD_256000: h->newtio.BaudRate = CBR_256000; break; - /* These are not defined in WinBase.h and might work or not */ - case SERIAL_BAUD_230400: h->newtio.BaudRate = 230400; break; - case SERIAL_BAUD_460800: h->newtio.BaudRate = 460800; break; - case SERIAL_BAUD_500000: h->newtio.BaudRate = 500000; break; - case SERIAL_BAUD_576000: h->newtio.BaudRate = 576000; break; - case SERIAL_BAUD_921600: h->newtio.BaudRate = 921600; break; - case SERIAL_BAUD_1000000: h->newtio.BaudRate = 1000000; break; - case SERIAL_BAUD_1500000: h->newtio.BaudRate = 1500000; break; - case SERIAL_BAUD_2000000: h->newtio.BaudRate = 2000000; break; - case SERIAL_BAUD_INVALID: - - default: - return PORT_ERR_UNKNOWN; - } - - switch (bits) { - case SERIAL_BITS_5: h->newtio.ByteSize = 5; break; - case SERIAL_BITS_6: h->newtio.ByteSize = 6; break; - case SERIAL_BITS_7: h->newtio.ByteSize = 7; break; - case SERIAL_BITS_8: h->newtio.ByteSize = 8; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (parity) { - case SERIAL_PARITY_NONE: h->newtio.Parity = NOPARITY; break; - case SERIAL_PARITY_EVEN: h->newtio.Parity = EVENPARITY; break; - case SERIAL_PARITY_ODD: h->newtio.Parity = ODDPARITY; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (stopbit) { - case SERIAL_STOPBIT_1: h->newtio.StopBits = ONESTOPBIT; break; - case SERIAL_STOPBIT_2: h->newtio.StopBits = TWOSTOPBITS; break; - - default: - return PORT_ERR_UNKNOWN; - } - - /* reset the settings */ - h->newtio.fOutxCtsFlow = FALSE; - h->newtio.fOutxDsrFlow = FALSE; - h->newtio.fOutX = FALSE; - h->newtio.fInX = FALSE; - h->newtio.fNull = 0; - h->newtio.fAbortOnError = 0; - - /* set the settings */ - serial_flush(h); - if (!SetCommState(h->fd, &h->newtio)) - return PORT_ERR_UNKNOWN; - - snprintf(h->setup_str, sizeof(h->setup_str), "%u %d%c%d", - serial_get_baud_int(baud), - serial_get_bits_int(bits), - serial_get_parity_str(parity), - serial_get_stopbit_int(stopbit) - ); - return PORT_ERR_OK; -} - -static port_err_t serial_w32_open(struct port_interface *port, - struct port_options *ops) -{ - serial_t *h; - - /* 1. check device name match */ - if (!((strlen(ops->device) == 4 || strlen(ops->device) == 5) - && !strncmp(ops->device, "COM", 3) && isdigit(ops->device[3])) - && !(!strncmp(ops->device, "\\\\.\\COM", strlen("\\\\.\\COM")) - && isdigit(ops->device[strlen("\\\\.\\COM")]))) - return PORT_ERR_NODEV; - - /* 2. check options */ - if (ops->baudRate == SERIAL_BAUD_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_bits(ops->serial_mode) == SERIAL_BITS_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_parity(ops->serial_mode) == SERIAL_PARITY_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_stopbit(ops->serial_mode) == SERIAL_STOPBIT_INVALID) - return PORT_ERR_UNKNOWN; - - /* 3. open it */ - h = serial_open(ops->device); - if (h == NULL) - return PORT_ERR_UNKNOWN; - - /* 4. set options */ - if (serial_setup(h, ops->baudRate, - serial_get_bits(ops->serial_mode), - serial_get_parity(ops->serial_mode), - serial_get_stopbit(ops->serial_mode) - ) != PORT_ERR_OK) { - serial_close(h); - return PORT_ERR_UNKNOWN; - } - - port->private = h; - return PORT_ERR_OK; -} - -static port_err_t serial_w32_close(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - serial_close(h); - port->private = NULL; - return PORT_ERR_OK; -} - -static port_err_t serial_w32_read(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - DWORD r; - uint8_t *pos = (uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - ReadFile(h->fd, pos, nbyte, &r, NULL); - if (r == 0) - return PORT_ERR_TIMEDOUT; - if (r < 0) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_w32_write(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - DWORD r; - uint8_t *pos = (uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - if (!WriteFile(h->fd, pos, nbyte, &r, NULL)) - return PORT_ERR_UNKNOWN; - if (r < 1) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_w32_gpio(struct port_interface *port, - serial_gpio_t n, int level) -{ - serial_t *h; - int bit; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - switch (n) { - case GPIO_RTS: - bit = level ? SETRTS : CLRRTS; - break; - - case GPIO_DTR: - bit = level ? SETDTR : CLRDTR; - break; - - case GPIO_BRK: - if (level == 0) - return PORT_ERR_OK; - if (EscapeCommFunction(h->fd, SETBREAK) == 0) - return PORT_ERR_UNKNOWN; - usleep(500000); - if (EscapeCommFunction(h->fd, CLRBREAK) == 0) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; - - default: - return PORT_ERR_UNKNOWN; - } - - /* handle RTS/DTR */ - if (EscapeCommFunction(h->fd, bit) == 0) - return PORT_ERR_UNKNOWN; - - return PORT_ERR_OK; -} - -static const char *serial_w32_get_cfg_str(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - return h ? h->setup_str : "INVALID"; -} - -struct port_interface port_serial = { - .name = "serial_w32", - .flags = PORT_BYTE | PORT_GVR_ETX | PORT_CMD_INIT | PORT_RETRY, - .open = serial_w32_open, - .close = serial_w32_close, - .read = serial_w32_read, - .write = serial_w32_write, - .gpio = serial_w32_gpio, - .get_cfg_str = serial_w32_get_cfg_str, -}; diff --git a/linux64/src/stm32flash_serial/src/stm32.c b/linux64/src/stm32flash_serial/src/stm32.c deleted file mode 100644 index 74047d244..000000000 --- a/linux64/src/stm32flash_serial/src/stm32.c +++ /dev/null @@ -1,1048 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright 2010 Geoffrey McRae - Copyright 2012-2014 Tormod Volden - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include - -#include "stm32.h" -#include "port.h" -#include "utils.h" - -#define STM32_ACK 0x79 -#define STM32_NACK 0x1F -#define STM32_BUSY 0x76 - -#define STM32_CMD_INIT 0x7F -#define STM32_CMD_GET 0x00 /* get the version and command supported */ -#define STM32_CMD_GVR 0x01 /* get version and read protection status */ -#define STM32_CMD_GID 0x02 /* get ID */ -#define STM32_CMD_RM 0x11 /* read memory */ -#define STM32_CMD_GO 0x21 /* go */ -#define STM32_CMD_WM 0x31 /* write memory */ -#define STM32_CMD_WM_NS 0x32 /* no-stretch write memory */ -#define STM32_CMD_ER 0x43 /* erase */ -#define STM32_CMD_EE 0x44 /* extended erase */ -#define STM32_CMD_EE_NS 0x45 /* extended erase no-stretch */ -#define STM32_CMD_WP 0x63 /* write protect */ -#define STM32_CMD_WP_NS 0x64 /* write protect no-stretch */ -#define STM32_CMD_UW 0x73 /* write unprotect */ -#define STM32_CMD_UW_NS 0x74 /* write unprotect no-stretch */ -#define STM32_CMD_RP 0x82 /* readout protect */ -#define STM32_CMD_RP_NS 0x83 /* readout protect no-stretch */ -#define STM32_CMD_UR 0x92 /* readout unprotect */ -#define STM32_CMD_UR_NS 0x93 /* readout unprotect no-stretch */ -#define STM32_CMD_CRC 0xA1 /* compute CRC */ -#define STM32_CMD_ERR 0xFF /* not a valid command */ - -#define STM32_RESYNC_TIMEOUT 35 /* seconds */ -#define STM32_MASSERASE_TIMEOUT 35 /* seconds */ -#define STM32_SECTERASE_TIMEOUT 5 /* seconds */ -#define STM32_BLKWRITE_TIMEOUT 1 /* seconds */ -#define STM32_WUNPROT_TIMEOUT 1 /* seconds */ -#define STM32_WPROT_TIMEOUT 1 /* seconds */ -#define STM32_RPROT_TIMEOUT 1 /* seconds */ - -#define STM32_CMD_GET_LENGTH 17 /* bytes in the reply */ - -struct stm32_cmd { - uint8_t get; - uint8_t gvr; - uint8_t gid; - uint8_t rm; - uint8_t go; - uint8_t wm; - uint8_t er; /* this may be extended erase */ - uint8_t wp; - uint8_t uw; - uint8_t rp; - uint8_t ur; - uint8_t crc; -}; - -/* Reset code for ARMv7-M (Cortex-M3) and ARMv6-M (Cortex-M0) - * see ARMv7-M or ARMv6-M Architecture Reference Manual (table B3-8) - * or "The definitive guide to the ARM Cortex-M3", section 14.4. - */ -static const uint8_t stm_reset_code[] = { - 0x01, 0x49, // ldr r1, [pc, #4] ; () - 0x02, 0x4A, // ldr r2, [pc, #8] ; () - 0x0A, 0x60, // str r2, [r1, #0] - 0xfe, 0xe7, // endless: b endless - 0x0c, 0xed, 0x00, 0xe0, // .word 0xe000ed0c = NVIC AIRCR register address - 0x04, 0x00, 0xfa, 0x05 // .word 0x05fa0004 = VECTKEY | SYSRESETREQ -}; - -static const uint32_t stm_reset_code_length = sizeof(stm_reset_code); - -extern const stm32_dev_t devices[]; - -static void stm32_warn_stretching(const char *f) -{ - fprintf(stderr, "Attention !!!\n"); - fprintf(stderr, "\tThis %s error could be caused by your I2C\n", f); - fprintf(stderr, "\tcontroller not accepting \"clock stretching\"\n"); - fprintf(stderr, "\tas required by bootloader.\n"); - fprintf(stderr, "\tCheck \"I2C.txt\" in stm32flash source code.\n"); -} - -static stm32_err_t stm32_get_ack_timeout(const stm32_t *stm, time_t timeout) -{ - struct port_interface *port = stm->port; - uint8_t byte; - port_err_t p_err; - time_t t0, t1; - - if (!(port->flags & PORT_RETRY)) - timeout = 0; - - if (timeout) - time(&t0); - - do { - p_err = port->read(port, &byte, 1); - if (p_err == PORT_ERR_TIMEDOUT && timeout) { - time(&t1); - if (t1 < t0 + timeout) - continue; - } - - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to read ACK byte\n"); - return STM32_ERR_UNKNOWN; - } - - if (byte == STM32_ACK) - return STM32_ERR_OK; - if (byte == STM32_NACK) - return STM32_ERR_NACK; - if (byte != STM32_BUSY) { - fprintf(stderr, "Got byte 0x%02x instead of ACK\n", - byte); - return STM32_ERR_UNKNOWN; - } - } while (1); -} - -static stm32_err_t stm32_get_ack(const stm32_t *stm) -{ - return stm32_get_ack_timeout(stm, 0); -} - -static stm32_err_t stm32_send_command_timeout(const stm32_t *stm, - const uint8_t cmd, - time_t timeout) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - port_err_t p_err; - uint8_t buf[2]; - - buf[0] = cmd; - buf[1] = cmd ^ 0xFF; - p_err = port->write(port, buf, 2); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to send command\n"); - return STM32_ERR_UNKNOWN; - } - s_err = stm32_get_ack_timeout(stm, timeout); - if (s_err == STM32_ERR_OK) - return STM32_ERR_OK; - if (s_err == STM32_ERR_NACK) - fprintf(stderr, "Got NACK from device on command 0x%02x\n", cmd); - else - fprintf(stderr, "Unexpected reply from device on command 0x%02x\n", cmd); - return STM32_ERR_UNKNOWN; -} - -static stm32_err_t stm32_send_command(const stm32_t *stm, const uint8_t cmd) -{ - return stm32_send_command_timeout(stm, cmd, 0); -} - -/* if we have lost sync, send a wrong command and expect a NACK */ -static stm32_err_t stm32_resync(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - port_err_t p_err; - uint8_t buf[2], ack; - time_t t0, t1; - - time(&t0); - t1 = t0; - - buf[0] = STM32_CMD_ERR; - buf[1] = STM32_CMD_ERR ^ 0xFF; - while (t1 < t0 + STM32_RESYNC_TIMEOUT) { - p_err = port->write(port, buf, 2); - if (p_err != PORT_ERR_OK) { - usleep(500000); - time(&t1); - continue; - } - p_err = port->read(port, &ack, 1); - if (p_err != PORT_ERR_OK) { - time(&t1); - continue; - } - if (ack == STM32_NACK) - return STM32_ERR_OK; - time(&t1); - } - return STM32_ERR_UNKNOWN; -} - -/* - * some command receive reply frame with variable length, and length is - * embedded in reply frame itself. - * We can guess the length, but if we guess wrong the protocol gets out - * of sync. - * Use resync for frame oriented interfaces (e.g. I2C) and byte-by-byte - * read for byte oriented interfaces (e.g. UART). - * - * to run safely, data buffer should be allocated for 256+1 bytes - * - * len is value of the first byte in the frame. - */ -static stm32_err_t stm32_guess_len_cmd(const stm32_t *stm, uint8_t cmd, - uint8_t *data, unsigned int len) -{ - struct port_interface *port = stm->port; - port_err_t p_err; - - if (stm32_send_command(stm, cmd) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - if (port->flags & PORT_BYTE) { - /* interface is UART-like */ - p_err = port->read(port, data, 1); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - len = data[0]; - p_err = port->read(port, data + 1, len + 1); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - return STM32_ERR_OK; - } - - p_err = port->read(port, data, len + 2); - if (p_err == PORT_ERR_OK && len == data[0]) - return STM32_ERR_OK; - if (p_err != PORT_ERR_OK) { - /* restart with only one byte */ - if (stm32_resync(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - if (stm32_send_command(stm, cmd) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - p_err = port->read(port, data, 1); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - } - - fprintf(stderr, "Re sync (len = %d)\n", data[0]); - if (stm32_resync(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - len = data[0]; - if (stm32_send_command(stm, cmd) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - p_err = port->read(port, data, len + 2); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - return STM32_ERR_OK; -} - -/* - * Some interface, e.g. UART, requires a specific init sequence to let STM32 - * autodetect the interface speed. - * The sequence is only required one time after reset. - * stm32flash has command line flag "-c" to prevent sending the init sequence - * in case it was already sent before. - * User can easily forget adding "-c". In this case the bootloader would - * interpret the init sequence as part of a command message, then waiting for - * the rest of the message blocking the interface. - * This function sends the init sequence and, in case of timeout, recovers - * the interface. - */ -static stm32_err_t stm32_send_init_seq(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - port_err_t p_err; - uint8_t byte, cmd = STM32_CMD_INIT; - - p_err = port->write(port, &cmd, 1); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to send init to device\n"); - return STM32_ERR_UNKNOWN; - } - p_err = port->read(port, &byte, 1); - if (p_err == PORT_ERR_OK && byte == STM32_ACK) - return STM32_ERR_OK; - if (p_err == PORT_ERR_OK && byte == STM32_NACK) { - /* We could get error later, but let's continue, for now. */ - fprintf(stderr, - "Warning: the interface was not closed properly.\n"); - return STM32_ERR_OK; - } - if (p_err != PORT_ERR_TIMEDOUT) { - fprintf(stderr, "Failed to init device.\n"); - return STM32_ERR_UNKNOWN; - } - - /* - * Check if previous STM32_CMD_INIT was taken as first byte - * of a command. Send a new byte, we should get back a NACK. - */ - p_err = port->write(port, &cmd, 1); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to send init to device\n"); - return STM32_ERR_UNKNOWN; - } - p_err = port->read(port, &byte, 1); - if (p_err == PORT_ERR_OK && byte == STM32_NACK) - return STM32_ERR_OK; - fprintf(stderr, "Failed to init device.\n"); - return STM32_ERR_UNKNOWN; -} - -/* find newer command by higher code */ -#define newer(prev, a) (((prev) == STM32_CMD_ERR) \ - ? (a) \ - : (((prev) > (a)) ? (prev) : (a))) - -stm32_t *stm32_init(struct port_interface *port, const char init) -{ - uint8_t len, val, buf[257]; - stm32_t *stm; - int i, new_cmds; - - stm = calloc(sizeof(stm32_t), 1); - stm->cmd = malloc(sizeof(stm32_cmd_t)); - memset(stm->cmd, STM32_CMD_ERR, sizeof(stm32_cmd_t)); - stm->port = port; - - if ((port->flags & PORT_CMD_INIT) && init) - if (stm32_send_init_seq(stm) != STM32_ERR_OK) - return NULL; - - /* get the version and read protection status */ - if (stm32_send_command(stm, STM32_CMD_GVR) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - /* From AN, only UART bootloader returns 3 bytes */ - len = (port->flags & PORT_GVR_ETX) ? 3 : 1; - if (port->read(port, buf, len) != PORT_ERR_OK) - return NULL; - stm->version = buf[0]; - stm->option1 = (port->flags & PORT_GVR_ETX) ? buf[1] : 0; - stm->option2 = (port->flags & PORT_GVR_ETX) ? buf[2] : 0; - if (stm32_get_ack(stm) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - /* get the bootloader information */ - len = STM32_CMD_GET_LENGTH; - if (port->cmd_get_reply) - for (i = 0; port->cmd_get_reply[i].length; i++) - if (stm->version == port->cmd_get_reply[i].version) { - len = port->cmd_get_reply[i].length; - break; - } - if (stm32_guess_len_cmd(stm, STM32_CMD_GET, buf, len) != STM32_ERR_OK) - return NULL; - len = buf[0] + 1; - stm->bl_version = buf[1]; - new_cmds = 0; - for (i = 1; i < len; i++) { - val = buf[i + 1]; - switch (val) { - case STM32_CMD_GET: - stm->cmd->get = val; break; - case STM32_CMD_GVR: - stm->cmd->gvr = val; break; - case STM32_CMD_GID: - stm->cmd->gid = val; break; - case STM32_CMD_RM: - stm->cmd->rm = val; break; - case STM32_CMD_GO: - stm->cmd->go = val; break; - case STM32_CMD_WM: - case STM32_CMD_WM_NS: - stm->cmd->wm = newer(stm->cmd->wm, val); - break; - case STM32_CMD_ER: - case STM32_CMD_EE: - case STM32_CMD_EE_NS: - stm->cmd->er = newer(stm->cmd->er, val); - break; - case STM32_CMD_WP: - case STM32_CMD_WP_NS: - stm->cmd->wp = newer(stm->cmd->wp, val); - break; - case STM32_CMD_UW: - case STM32_CMD_UW_NS: - stm->cmd->uw = newer(stm->cmd->uw, val); - break; - case STM32_CMD_RP: - case STM32_CMD_RP_NS: - stm->cmd->rp = newer(stm->cmd->rp, val); - break; - case STM32_CMD_UR: - case STM32_CMD_UR_NS: - stm->cmd->ur = newer(stm->cmd->ur, val); - break; - case STM32_CMD_CRC: - stm->cmd->crc = newer(stm->cmd->crc, val); - break; - default: - if (new_cmds++ == 0) - fprintf(stderr, - "GET returns unknown commands (0x%2x", - val); - else - fprintf(stderr, ", 0x%2x", val); - } - } - if (new_cmds) - fprintf(stderr, ")\n"); - if (stm32_get_ack(stm) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - if (stm->cmd->get == STM32_CMD_ERR - || stm->cmd->gvr == STM32_CMD_ERR - || stm->cmd->gid == STM32_CMD_ERR) { - fprintf(stderr, "Error: bootloader did not returned correct information from GET command\n"); - return NULL; - } - - /* get the device ID */ - if (stm32_guess_len_cmd(stm, stm->cmd->gid, buf, 1) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - len = buf[0] + 1; - if (len < 2) { - stm32_close(stm); - fprintf(stderr, "Only %d bytes sent in the PID, unknown/unsupported device\n", len); - return NULL; - } - stm->pid = (buf[1] << 8) | buf[2]; - if (len > 2) { - fprintf(stderr, "This bootloader returns %d extra bytes in PID:", len); - for (i = 2; i <= len ; i++) - fprintf(stderr, " %02x", buf[i]); - fprintf(stderr, "\n"); - } - if (stm32_get_ack(stm) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - stm->dev = devices; - while (stm->dev->id != 0x00 && stm->dev->id != stm->pid) - ++stm->dev; - - if (!stm->dev->id) { - fprintf(stderr, "Unknown/unsupported device (Device ID: 0x%03x)\n", stm->pid); - stm32_close(stm); - return NULL; - } - - return stm; -} - -void stm32_close(stm32_t *stm) -{ - if (stm) - free(stm->cmd); - free(stm); -} - -stm32_err_t stm32_read_memory(const stm32_t *stm, uint32_t address, - uint8_t data[], unsigned int len) -{ - struct port_interface *port = stm->port; - uint8_t buf[5]; - - if (!len) - return STM32_ERR_OK; - - if (len > 256) { - fprintf(stderr, "Error: READ length limit at 256 bytes\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->rm == STM32_CMD_ERR) { - fprintf(stderr, "Error: READ command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->rm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_send_command(stm, len - 1) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (port->read(port, data, len) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - return STM32_ERR_OK; -} - -stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address, - const uint8_t data[], unsigned int len) -{ - struct port_interface *port = stm->port; - uint8_t cs, buf[256 + 2]; - unsigned int i, aligned_len; - stm32_err_t s_err; - - if (!len) - return STM32_ERR_OK; - - if (len > 256) { - fprintf(stderr, "Error: READ length limit at 256 bytes\n"); - return STM32_ERR_UNKNOWN; - } - - /* must be 32bit aligned */ - if (address & 0x3 || len & 0x3) { - fprintf(stderr, "Error: WRITE address and length must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->wm == STM32_CMD_ERR) { - fprintf(stderr, "Error: WRITE command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - /* send the address and checksum */ - if (stm32_send_command(stm, stm->cmd->wm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - aligned_len = (len + 3) & ~3; - cs = aligned_len - 1; - buf[0] = aligned_len - 1; - for (i = 0; i < len; i++) { - cs ^= data[i]; - buf[i + 1] = data[i]; - } - /* padding data */ - for (i = len; i < aligned_len; i++) { - cs ^= 0xFF; - buf[i + 1] = 0xFF; - } - buf[aligned_len + 1] = cs; - if (port->write(port, buf, aligned_len + 2) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_BLKWRITE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->wm != STM32_CMD_WM_NS) - stm32_warn_stretching("write"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_wunprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->uw == STM32_CMD_ERR) { - fprintf(stderr, "Error: WRITE UNPROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->uw) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_WUNPROT_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to WRITE UNPROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->uw != STM32_CMD_UW_NS) - stm32_warn_stretching("WRITE UNPROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_wprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->wp == STM32_CMD_ERR) { - fprintf(stderr, "Error: WRITE PROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->wp) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_WPROT_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to WRITE PROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->wp != STM32_CMD_WP_NS) - stm32_warn_stretching("WRITE PROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_runprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->ur == STM32_CMD_ERR) { - fprintf(stderr, "Error: READOUT UNPROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->ur) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to READOUT UNPROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->ur != STM32_CMD_UR_NS) - stm32_warn_stretching("READOUT UNPROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_readprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->rp == STM32_CMD_ERR) { - fprintf(stderr, "Error: READOUT PROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->rp) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_RPROT_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to READOUT PROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->rp != STM32_CMD_RP_NS) - stm32_warn_stretching("READOUT PROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, uint8_t pages) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - port_err_t p_err; - - if (!pages) - return STM32_ERR_OK; - - if (stm->cmd->er == STM32_CMD_ERR) { - fprintf(stderr, "Error: ERASE command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->er) != STM32_ERR_OK) { - fprintf(stderr, "Can't initiate chip erase!\n"); - return STM32_ERR_UNKNOWN; - } - - /* The erase command reported by the bootloader is either 0x43, 0x44 or 0x45 */ - /* 0x44 is Extended Erase, a 2 byte based protocol and needs to be handled differently. */ - /* 0x45 is clock no-stretching version of Extended Erase for I2C port. */ - if (stm->cmd->er != STM32_CMD_ER) { - /* Not all chips using Extended Erase support mass erase */ - /* Currently known as not supporting mass erase is the Ultra Low Power STM32L15xx range */ - /* So if someone has not overridden the default, but uses one of these chips, take it out of */ - /* mass erase mode, so it will be done page by page. This maximum might not be correct either! */ - if (stm->pid == 0x416 && pages == 0xFF) - pages = 0xF8; /* works for the STM32L152RB with 128Kb flash */ - - if (pages == 0xFF) { - uint8_t buf[3]; - - /* 0xFFFF the magic number for mass erase */ - buf[0] = 0xFF; - buf[1] = 0xFF; - buf[2] = 0x00; /* checksum */ - if (port->write(port, buf, 3) != PORT_ERR_OK) { - fprintf(stderr, "Mass erase error.\n"); - return STM32_ERR_UNKNOWN; - } - s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Mass erase failed. Try specifying the number of pages to be erased.\n"); - if (port->flags & PORT_STRETCH_W - && stm->cmd->er != STM32_CMD_EE_NS) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; - } - - uint16_t pg_num; - uint8_t pg_byte; - uint8_t cs = 0; - uint8_t *buf; - int i = 0; - - buf = malloc(2 + 2 * pages + 1); - if (!buf) - return STM32_ERR_UNKNOWN; - - /* Number of pages to be erased - 1, two bytes, MSB first */ - pg_byte = (pages - 1) >> 8; - buf[i++] = pg_byte; - cs ^= pg_byte; - pg_byte = (pages - 1) & 0xFF; - buf[i++] = pg_byte; - cs ^= pg_byte; - - for (pg_num = spage; pg_num < spage + pages; pg_num++) { - pg_byte = pg_num >> 8; - cs ^= pg_byte; - buf[i++] = pg_byte; - pg_byte = pg_num & 0xFF; - cs ^= pg_byte; - buf[i++] = pg_byte; - } - buf[i++] = cs; - p_err = port->write(port, buf, i); - free(buf); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Page-by-page erase error.\n"); - return STM32_ERR_UNKNOWN; - } - - s_err = stm32_get_ack_timeout(stm, pages * STM32_SECTERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Page-by-page erase failed. Check the maximum pages your device supports.\n"); - if (port->flags & PORT_STRETCH_W - && stm->cmd->er != STM32_CMD_EE_NS) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - - return STM32_ERR_OK; - } - - /* And now the regular erase (0x43) for all other chips */ - if (pages == 0xFF) { - s_err = stm32_send_command_timeout(stm, 0xFF, STM32_MASSERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; - } else { - uint8_t cs = 0; - uint8_t pg_num; - uint8_t *buf; - int i = 0; - - buf = malloc(1 + pages + 1); - if (!buf) - return STM32_ERR_UNKNOWN; - - buf[i++] = pages - 1; - cs ^= (pages-1); - for (pg_num = spage; pg_num < (pages + spage); pg_num++) { - buf[i++] = pg_num; - cs ^= pg_num; - } - buf[i++] = cs; - p_err = port->write(port, buf, i); - free(buf); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Erase failed.\n"); - return STM32_ERR_UNKNOWN; - } - s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; - } -} - -static stm32_err_t stm32_run_raw_code(const stm32_t *stm, - uint32_t target_address, - const uint8_t *code, uint32_t code_size) -{ - uint32_t stack_le = le_u32(0x20002000); - uint32_t code_address_le = le_u32(target_address + 8); - uint32_t length = code_size + 8; - uint8_t *mem, *pos; - uint32_t address, w; - - /* Must be 32-bit aligned */ - if (target_address & 0x3) { - fprintf(stderr, "Error: code address must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - mem = malloc(length); - if (!mem) - return STM32_ERR_UNKNOWN; - - memcpy(mem, &stack_le, sizeof(uint32_t)); - memcpy(mem + 4, &code_address_le, sizeof(uint32_t)); - memcpy(mem + 8, code, code_size); - - pos = mem; - address = target_address; - while (length > 0) { - w = length > 256 ? 256 : length; - if (stm32_write_memory(stm, address, pos, w) != STM32_ERR_OK) { - free(mem); - return STM32_ERR_UNKNOWN; - } - - address += w; - pos += w; - length -= w; - } - - free(mem); - return stm32_go(stm, target_address); -} - -stm32_err_t stm32_go(const stm32_t *stm, uint32_t address) -{ - struct port_interface *port = stm->port; - uint8_t buf[5]; - - if (stm->cmd->go == STM32_CMD_ERR) { - fprintf(stderr, "Error: GO command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->go) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - return STM32_ERR_OK; -} - -stm32_err_t stm32_reset_device(const stm32_t *stm) -{ - uint32_t target_address = stm->dev->ram_start; - - return stm32_run_raw_code(stm, target_address, stm_reset_code, stm_reset_code_length); -} - -stm32_err_t stm32_crc_memory(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc) -{ - struct port_interface *port = stm->port; - uint8_t buf[5]; - - if (address & 0x3 || length & 0x3) { - fprintf(stderr, "Start and end addresses must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->crc == STM32_CMD_ERR) { - fprintf(stderr, "Error: CRC command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->crc) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = length >> 24; - buf[1] = (length >> 16) & 0xFF; - buf[2] = (length >> 8) & 0xFF; - buf[3] = length & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (port->read(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (buf[4] != (buf[0] ^ buf[1] ^ buf[2] ^ buf[3])) - return STM32_ERR_UNKNOWN; - - *crc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; - return STM32_ERR_OK; -} - -/* - * CRC computed by STM32 is similar to the standard crc32_be() - * implemented, for example, in Linux kernel in ./lib/crc32.c - * But STM32 computes it on units of 32 bits word and swaps the - * bytes of the word before the computation. - * Due to byte swap, I cannot use any CRC available in existing - * libraries, so here is a simple not optimized implementation. - */ -#define CRCPOLY_BE 0x04c11db7 -#define CRC_MSBMASK 0x80000000 -#define CRC_INIT_VALUE 0xFFFFFFFF -uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len) -{ - int i; - uint32_t data; - - if (len & 0x3) { - fprintf(stderr, "Buffer length must be multiple of 4 bytes\n"); - return 0; - } - - while (len) { - data = *buf++; - data |= *buf++ << 8; - data |= *buf++ << 16; - data |= *buf++ << 24; - len -= 4; - - crc ^= data; - - for (i = 0; i < 32; i++) - if (crc & CRC_MSBMASK) - crc = (crc << 1) ^ CRCPOLY_BE; - else - crc = (crc << 1); - } - return crc; -} - -stm32_err_t stm32_crc_wrapper(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc) -{ - uint8_t buf[256]; - uint32_t start, total_len, len, current_crc; - - if (address & 0x3 || length & 0x3) { - fprintf(stderr, "Start and end addresses must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->crc != STM32_CMD_ERR) - return stm32_crc_memory(stm, address, length, crc); - - start = address; - total_len = length; - current_crc = CRC_INIT_VALUE; - while (length) { - len = length > 256 ? 256 : length; - if (stm32_read_memory(stm, address, buf, len) != STM32_ERR_OK) { - fprintf(stderr, - "Failed to read memory at address 0x%08x, target write-protected?\n", - address); - return STM32_ERR_UNKNOWN; - } - current_crc = stm32_sw_crc(current_crc, buf, len); - length -= len; - address += len; - - fprintf(stderr, - "\rCRC address 0x%08x (%.2f%%) ", - address, - (100.0f / (float)total_len) * (float)(address - start) - ); - fflush(stderr); - } - fprintf(stderr, "Done.\n"); - *crc = current_crc; - return STM32_ERR_OK; -} diff --git a/linux64/src/stm32flash_serial/src/stm32.h b/linux64/src/stm32flash_serial/src/stm32.h deleted file mode 100644 index 1688fcb4b..000000000 --- a/linux64/src/stm32flash_serial/src/stm32.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _STM32_H -#define _STM32_H - -#include -#include "serial.h" - -#define STM32_MAX_RX_FRAME 256 /* cmd read memory */ -#define STM32_MAX_TX_FRAME (1 + 256 + 1) /* cmd write memory */ - -typedef enum { - STM32_ERR_OK = 0, - STM32_ERR_UNKNOWN, /* Generic error */ - STM32_ERR_NACK, - STM32_ERR_NO_CMD, /* Command not available in bootloader */ -} stm32_err_t; - -typedef struct stm32 stm32_t; -typedef struct stm32_cmd stm32_cmd_t; -typedef struct stm32_dev stm32_dev_t; - -struct stm32 { - const serial_t *serial; - struct port_interface *port; - uint8_t bl_version; - uint8_t version; - uint8_t option1, option2; - uint16_t pid; - stm32_cmd_t *cmd; - const stm32_dev_t *dev; -}; - -struct stm32_dev { - uint16_t id; - const char *name; - uint32_t ram_start, ram_end; - uint32_t fl_start, fl_end; - uint16_t fl_pps; // pages per sector - uint16_t fl_ps; // page size - uint32_t opt_start, opt_end; - uint32_t mem_start, mem_end; -}; - -stm32_t *stm32_init(struct port_interface *port, const char init); -void stm32_close(stm32_t *stm); -stm32_err_t stm32_read_memory(const stm32_t *stm, uint32_t address, - uint8_t data[], unsigned int len); -stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address, - const uint8_t data[], unsigned int len); -stm32_err_t stm32_wunprot_memory(const stm32_t *stm); -stm32_err_t stm32_wprot_memory(const stm32_t *stm); -stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, - uint8_t pages); -stm32_err_t stm32_go(const stm32_t *stm, uint32_t address); -stm32_err_t stm32_reset_device(const stm32_t *stm); -stm32_err_t stm32_readprot_memory(const stm32_t *stm); -stm32_err_t stm32_runprot_memory(const stm32_t *stm); -stm32_err_t stm32_crc_memory(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc); -stm32_err_t stm32_crc_wrapper(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc); -uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len); - -#endif - diff --git a/linux64/src/stm32flash_serial/src/stm32flash.1 b/linux64/src/stm32flash_serial/src/stm32flash.1 deleted file mode 100644 index d37292f6a..000000000 --- a/linux64/src/stm32flash_serial/src/stm32flash.1 +++ /dev/null @@ -1,407 +0,0 @@ -.TH STM32FLASH 1 "2013\-11\-03" STM32FLASH "User command" -.SH NAME -stm32flash \- flashing utility for STM32 and STM32W through UART or I2C -.SH SYNOPSIS -.B stm32flash -.RB [ \-cfhjkouvCR ] -.RB [ \-a -.IR bus_address ] -.RB [ \-b -.IR baud_rate ] -.RB [ \-m -.IR serial_mode ] -.RB [ \-r -.IR filename ] -.RB [ \-w -.IR filename ] -.RB [ \-e -.IR num ] -.RB [ \-n -.IR count ] -.RB [ \-g -.IR address ] -.RB [ \-s -.IR start_page ] -.RB [ \-S -.IR address [: length ]] -.RB [ \-F -.IR RX_length [: TX_length ]] -.RB [ \-i -.IR GPIO_string ] -.RI [ tty_device -.R | -.IR i2c_device ] - -.SH DESCRIPTION -.B stm32flash -reads or writes the flash memory of STM32 and STM32W. - -It requires the STM32[W] to embed a bootloader compliant with ST -application note AN3155. -.B stm32flash -uses the serial port -.I tty_device -to interact with the bootloader of STM32[W]. - -.SH OPTIONS -.TP -.BI "\-a" " bus_address" -Specify address on bus for -.IR i2c_device . -This option is mandatory for I2C interface. - -.TP -.BI "\-b" " baud_rate" -Specify baud rate speed of -.IR tty_device . -Please notice that the ST bootloader can automatically detect the baud rate, -as explaned in chapter 2 of AN3155. -This option could be required together with option -.B "\-c" -or if following interaction with bootloader is expected. -Default is -.IR 57600 . - -.TP -.BI "\-m" " mode" -Specify the format of UART data. -.I mode -is a three characters long string where each character specifies, in -this strict order, character size, parity and stop bits. -The only values currenly used are -.I 8e1 -for standard STM32 bootloader and -.I 8n1 -for standard STM32W bootloader. -Default is -.IR 8e1 . - -.TP -.BI "\-r" " filename" -Specify to read the STM32[W] flash and write its content in -.I filename -in raw binary format (see below -.BR "FORMAT CONVERSION" ). - -.TP -.BI "\-w" " filename" -Specify to write the STM32[W] flash with the content of -.IR filename . -File format can be either raw binary or intel hex (see below -.BR "FORMAT CONVERSION" ). -The file format is automatically detected. -To by\-pass format detection and force binary mode (e.g. to -write an intel hex content in STM32[W] flash), use -.B \-f -option. - -.TP -.B \-u -Specify to disable write\-protection from STM32[W] flash. -The STM32[W] will be reset after this operation. - -.TP -.B \-j -Enable the flash read\-protection. - -.TP -.B \-k -Disable the flash read\-protection. - -.TP -.B \-o -Erase only. - -.TP -.BI "\-e" " num" -Specify to erase only -.I num -pages before writing the flash. Default is to erase the whole flash. With -.B \-e 0 -the flash would not be erased. - -.TP -.B \-v -Specify to verify flash content after write operation. - -.TP -.BI "\-n" " count" -Specify to retry failed writes up to -.I count -times. Default is 10 times. - -.TP -.BI "\-g" " address" -Specify address to start execution from (0 = flash start). - -.TP -.BI "\-s" " start_page" -Specify flash page offset (0 = flash start). - -.TP -.BI "\-S" " address" "[:" "length" "]" -Specify start address and optionally length for read/write/erase/crc operations. - -.TP -.BI "\-F" " RX_length" "[:" "TX_length" "]" -Specify the maximum frame size for the current interface. -Due to STM32 bootloader protocol, host will never handle frames bigger than -256 byte in RX or 258 byte in TX. -Due to current code, lowest limit in RX is 20 byte (to read a complete reply -of command GET). Minimum limit in TX is 5 byte, required by protocol. - -.TP -.B \-f -Force binary parser while reading file with -.BR "\-w" "." - -.TP -.B \-h -Show help. - -.TP -.B \-c -Specify to resume the existing UART connection and don't send initial -INIT sequence to detect baud rate. Baud rate must be kept the same as the -existing connection. This is useful if the reset fails. - -.TP -.BI "\-i" " GPIO_string" -Specify the GPIO sequences on the host to force STM32[W] to enter and -exit bootloader mode. GPIO can either be real GPIO connected from host to -STM32[W] beside the UART connection, or UART's modem signals used as -GPIO. (See below -.B BOOTLOADER GPIO SEQUENCE -for the format of -.I GPIO_string -and further explanation). - -.TP -.B \-C -Specify to compute CRC on memory content. -By default the CRC is computed on the whole flash content. -Use -.B "\-S" -to provide different memory address range. - -.TP -.B \-R -Specify to reset the device at exit. -This option is ignored if either -.BR "\-g" "," -.BR "\-j" "," -.B "\-k" -or -.B "\-u" -is also specified. - -.SH BOOTLOADER GPIO SEQUENCE -This feature is currently available on Linux host only. - -As explained in ST application note AN2606, after reset the STM32 will -execute either the application program in user flash or the bootloader, -depending on the level applied at specific pins of STM32 during reset. - -STM32 bootloader is automatically activated by configuring the pins -BOOT0="high" and BOOT1="low" and then by applying a reset. -Application program in user flash is activated by configuring the pin -BOOT0="low" (the level on BOOT1 is ignored) and then by applying a reset. - -When GPIO from host computer are connected to either configuration and -reset pins of STM32, -.B stm32flash -can control the host GPIO to reset STM32 and to force execution of -bootloader or execution of application program. - -The sequence of GPIO values to entry to and exit from bootloader mode is -provided with command line option -.B "\-i" -.IR "GPIO_string" . - -.PD 0 -The format of -.IR "GPIO_string" " is:" -.RS -GPIO_string = [entry sequence][:[exit sequence]] -.P -sequence = [\-]n[,sequence] -.RE -.P -In the above sequences, negative numbers correspond to GPIO at "low" level; -numbers without sign correspond to GPIO at "high" level. -The value "n" can either be the GPIO number on the host system or the -string "rts", "dtr" or "brk". The strings "rts" and "dtr" drive the -corresponding UART's modem lines RTS and DTR as GPIO. -The string "brk" forces the UART to send a BREAK sequence on TX line; -after BREAK the UART is returned in normal "non\-break" mode. -Note: the string "\-brk" has no effect and is ignored. -.PD - -.PD 0 -As example, let's suppose the following connection between host and STM32: -.IP \(bu 2 -host GPIO_3 connected to reset pin of STM32; -.IP \(bu 2 -host GPIO_4 connected to STM32 pin BOOT0; -.IP \(bu 2 -host GPIO_5 connected to STM32 pin BOOT1. -.PD -.P - -In this case, the sequence to enter in bootloader mode is: first put -GPIO_4="high" and GPIO_5="low"; then send reset pulse by GPIO_3="low" -followed by GPIO_3="high". -The corresponding string for -.I GPIO_string -is "4,\-5,\-3,3". - -To exit from bootloade and run the application program, the sequence is: -put GPIO_4="low"; then send reset pulse. -The corresponding string for -.I GPIO_string -is "\-4,\-3,3". - -The complete command line flag is "\-i 4,\-5,\-3,3:\-4,\-3,3". - -STM32W uses pad PA5 to select boot mode; if during reset PA5 is "low" then -STM32W will enter in bootloader mode; if PA5 is "high" it will execute the -program in flash. - -As example, supposing GPIO_3 connected to PA5 and GPIO_2 to STM32W's reset. -The command: -.PD 0 -.RS -stm32flash \-i \-3,\-2,2:3,\-2,2 /dev/ttyS0 -.RE -provides: -.IP \(bu 2 -entry sequence: GPIO_3=low, GPIO_2=low, GPIO_2=high -.IP \(bu 2 -exit sequence: GPIO_3=high, GPIO_2=low, GPIO_2=high -.PD - -.SH EXAMPLES -Get device information: -.RS -.PD 0 -.P -stm32flash /dev/ttyS0 -.PD -.RE - -Write with verify and then start execution: -.RS -.PD 0 -.P -stm32flash \-w filename \-v \-g 0x0 /dev/ttyS0 -.PD -.RE - -Read flash to file: -.RS -.PD 0 -.P -stm32flash \-r filename /dev/ttyS0 -.PD -.RE - -Start execution: -.RS -.PD 0 -.P -stm32flash \-g 0x0 /dev/ttyS0 -.PD -.RE - -Specify: -.PD 0 -.IP \(bu 2 -entry sequence: RTS=low, DTR=low, DTR=high -.IP \(bu 2 -exit sequence: RTS=high, DTR=low, DTR=high -.P -.RS -stm32flash \-i \-rts,\-dtr,dtr:rts,\-dtr,dtr /dev/ttyS0 -.PD -.RE - -.SH FORMAT CONVERSION -Flash images provided by ST or created with ST tools are often in file -format Motorola S\-Record. -Conversion between raw binary, intel hex and Motorola S\-Record can be -done through software package SRecord. - -.SH AUTHORS -The original software package -.B stm32flash -is written by -.I Geoffrey McRae -and is since 2012 maintained by -.IR "Tormod Volden " . - -Man page and extension to STM32W and I2C are written by -.IR "Antonio Borneo " . - -Please report any bugs at the project homepage -http://stm32flash.googlecode.com . - -.SH SEE ALSO -.BR "srec_cat" "(1)," " srec_intel" "(5)," " srec_motorola" "(5)." - -The communication protocol used by ST bootloader is documented in -following ST application notes, depending on communication port. -The current version of -.B stm32flash -only supports -.I UART -and -.I I2C -ports. -.PD 0 -.P -.IP \(bu 2 -AN3154: CAN protocol used in the STM32 bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/CD00264321.pdf -.RE - -.P -.IP \(bu 2 -AN3155: USART protocol used in the STM32(TM) bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/CD00264342.pdf -.RE - -.P -.IP \(bu 2 -AN4221: I2C protocol used in the STM32 bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/DM00072315.pdf -.RE - -.P -.IP \(bu 2 -AN4286: SPI protocol used in the STM32 bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/DM00081379.pdf -.RE - -.PD - - -Boot mode selection for STM32 is documented in ST application note -AN2606, available from the ST website: -.PD 0 -.P -http://www.st.com/web/en/resource/technical/document/application_note/CD00167594.pdf -.PD - -.SH LICENSE -.B stm32flash -is distributed under GNU GENERAL PUBLIC LICENSE Version 2. -Copy of the license is available within the source code in the file -.IR "gpl\-2.0.txt" . diff --git a/linux64/src/stm32flash_serial/src/utils.c b/linux64/src/stm32flash_serial/src/utils.c deleted file mode 100644 index 271bb3ed7..000000000 --- a/linux64/src/stm32flash_serial/src/utils.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include "utils.h" - -/* detect CPU endian */ -char cpu_le() { - const uint32_t cpu_le_test = 0x12345678; - return ((const unsigned char*)&cpu_le_test)[0] == 0x78; -} - -uint32_t be_u32(const uint32_t v) { - if (cpu_le()) - return ((v & 0xFF000000) >> 24) | - ((v & 0x00FF0000) >> 8) | - ((v & 0x0000FF00) << 8) | - ((v & 0x000000FF) << 24); - return v; -} - -uint32_t le_u32(const uint32_t v) { - if (!cpu_le()) - return ((v & 0xFF000000) >> 24) | - ((v & 0x00FF0000) >> 8) | - ((v & 0x0000FF00) << 8) | - ((v & 0x000000FF) << 24); - return v; -} diff --git a/linux64/src/stm32flash_serial/src/utils.h b/linux64/src/stm32flash_serial/src/utils.h deleted file mode 100644 index a8d37d2d5..000000000 --- a/linux64/src/stm32flash_serial/src/utils.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _H_UTILS -#define _H_UTILS - -#include - -char cpu_le(); -uint32_t be_u32(const uint32_t v); -uint32_t le_u32(const uint32_t v); - -#endif diff --git a/macosx/src/stm32flash_serial/src/AUTHORS b/macosx/src/stm32flash_serial/src/AUTHORS deleted file mode 100644 index d096f2205..000000000 --- a/macosx/src/stm32flash_serial/src/AUTHORS +++ /dev/null @@ -1,19 +0,0 @@ -Authors ordered by first contribution. - -Geoffrey McRae -Bret Olmsted -Tormod Volden -Jakob Malm -Reuben Dowle -Matthias Kubisch -Paul Fertser -Daniel Strnad -Jérémie Rapin -Christian Pointner -Mats Erik Andersson -Alexey Borovik -Antonio Borneo -Armin van der Togt -Brian Silverman -Georg Hofmann -Luis Rodrigues diff --git a/macosx/src/stm32flash_serial/src/Android.mk b/macosx/src/stm32flash_serial/src/Android.mk deleted file mode 100644 index 7be3d0018..000000000 --- a/macosx/src/stm32flash_serial/src/Android.mk +++ /dev/null @@ -1,20 +0,0 @@ -TOP_LOCAL_PATH := $(call my-dir) - -include $(call all-named-subdir-makefiles, parsers) - -LOCAL_PATH := $(TOP_LOCAL_PATH) - -include $(CLEAR_VARS) -LOCAL_MODULE := stm32flash -LOCAL_SRC_FILES := \ - dev_table.c \ - i2c.c \ - init.c \ - main.c \ - port.c \ - serial_common.c \ - serial_platform.c \ - stm32.c \ - utils.c -LOCAL_STATIC_LIBRARIES := libparsers -include $(BUILD_EXECUTABLE) diff --git a/macosx/src/stm32flash_serial/src/HOWTO b/macosx/src/stm32flash_serial/src/HOWTO deleted file mode 100644 index d8f32eb04..000000000 --- a/macosx/src/stm32flash_serial/src/HOWTO +++ /dev/null @@ -1,35 +0,0 @@ -Add new interfaces: -===================================================================== -Current version 0.4 supports the following interfaces: -- UART Windows (either "COMn" and "\\.\COMn"); -- UART posix/Linux (e.g. "/dev/ttyUSB0"); -- I2C Linux through standard driver "i2c-dev" (e.g. "/dev/i2c-n"). - -Starting from version 0.4, the back-end of stm32flash is modular and -ready to be expanded to support new interfaces. -I'm planning adding SPI on Linux through standard driver "spidev". -You are invited to contribute with more interfaces. - -To add a new interface you need to add a new file, populate the struct -port_interface (check at the end of files i2c.c, serial_posix.c and -serial_w32.c) and provide the relative functions to operate on the -interface: open/close, read/write, get_cfg_str and the optional gpio. -The include the new drive in Makefile and register the new struct -port_interface in file port.c in struct port_interface *ports[]. - -There are several USB-I2C adapter in the market, each providing its -own libraries to communicate with the I2C bus. -Could be interesting to provide as back-end a bridge between stm32flash -and such libraries (I have no plan on this item). - - -Add new STM32 devices: -===================================================================== -Add a new line in file dev_table.c, in table devices[]. -The fields of the table are listed in stm32.h, struct stm32_dev. - - -Cross compile on Linux host for Windows target with MinGW: -===================================================================== -I'm using a 64 bit Arch Linux machines, and I usually run: - make CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-ar diff --git a/macosx/src/stm32flash_serial/src/I2C.txt b/macosx/src/stm32flash_serial/src/I2C.txt deleted file mode 100644 index 4c05ff62d..000000000 --- a/macosx/src/stm32flash_serial/src/I2C.txt +++ /dev/null @@ -1,94 +0,0 @@ -About I2C back-end communication in stm32flash -========================================================================== - -Starting from version v0.4, beside the serial communication port, -stm32flash adds support for I2C port to talk with STM32 bootloader. - -The current I2C back-end supports only the API provided by Linux kernel -driver "i2c-dev", so only I2C controllers with Linux kernel driver can be -used. -In Linux source code, most of the drivers for I2C and SMBUS controllers -are in - ./drivers/i2c/busses/ -Only I2C is supported by STM32 bootloader, so check the section below -about SMBUS. -No I2C support for Windows is available in stm32flash v0.4. - -Thanks to the new modular back-end, stm32flash can be easily extended to -support new back-ends and API. Check HOWTO file in stm32flash source code -for details. - -In the market there are several USB-to-I2C dongles; most of them are not -supported by kernel drivers. Manufacturer provide proprietary userspace -libraries using not standardized API. -These API and dongles could be supported in feature versions. - -There are currently 3 versions of STM32 bootloader for I2C communications: -- v1.0 using I2C clock stretching synchronization between host and STM32; -- v1.1 superset of v1.0, adds non stretching commands; -- v1.2 superset of v1.1, adds CRC command and compatibility with i2cdetect. -Details in ST application note AN2606. -All the bootloaders above are tested and working with stm32flash. - - -SMBUS controllers -========================================================================== - -Almost 50% of the drivers in Linux source code folder - ./drivers/i2c/busses/ -are for controllers that "only" support SMBUS protocol. They can NOT -operate with STM32 bootloader. -To identify if your controller supports I2C, use command: - i2cdetect -F n -where "n" is the number of the I2C interface (e.g. n=3 for "/dev/i2c-3"). -Controllers that supports I2C will report - I2C yes -Controller that support both I2C and SMBUS are ok. - -If you are interested on details about SMBUS protocol, you can download -the current specs from - http://smbus.org/specs/smbus20.pdf -and you can read the files in Linux source code - ./Documentation/i2c/i2c-protocol - ./Documentation/i2c/smbus-protocol - - -About bootloader v1.0 -========================================================================== - -Version v1.0 can have issues with some I2C controllers due to use of clock -stretching during commands that require long operations, like flash erase -and programming. - -Clock stretching is a technique to synchronize host and I2C device. When -I2C device wants to force a delay in the communication, it push "low" the -I2C clock; the I2C controller detects it and waits until I2C clock returns -"high". -Most I2C controllers set a "timeout" for clock stretching, ranging from -few milli-seconds to seconds depending on specific HW or SW driver. - -It is possible that the timeout in your I2C controller is smaller than the -delay required for flash erase or programming. In this case the I2C -controller will timeout and report error to stm32flash. -There is no possibility for stm32flash to retry, so it can only signal the -error and exit. - -To by-pass the issue with bootloader v1.0 you can modify the kernel driver -of your I2C controller. Not an easy job, since every controller has its own -way to handle the timeout. - -In my case I'm using the I2C controller integrated in the VGA port of my -laptop HP EliteBook 8460p. I built the 0.25$ VGA-to-I2C adapter reported in - http://www.paintyourdragon.com/?p=43 -To change the timeout of the I2C controller I had to modify the kernel file - drivers/gpu/drm/radeon/radeon_i2c.c -line 969 -- i2c->bit.timeout = usecs_to_jiffies(2200); /* from VESA */ -+ i2c->bit.timeout = msecs_to_jiffies(5000); /* 5s for STM32 */ -and recompile it. -Then - $> modprobe i2c-dev - $> chmod 666 /dev/i2c-7 - #> stm32flash -a 0x39 /dev/i2c-7 - -2014-09-16 Antonio Borneo diff --git a/macosx/src/stm32flash_serial/src/Makefile b/macosx/src/stm32flash_serial/src/Makefile deleted file mode 100644 index 0328d5588..000000000 --- a/macosx/src/stm32flash_serial/src/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -PREFIX = /usr/local -CFLAGS += -Wall -g - -INSTALL = install - -OBJS = dev_table.o \ - i2c.o \ - init.o \ - main.o \ - port.o \ - serial_common.o \ - serial_platform.o \ - stm32.o \ - utils.o - -LIBOBJS = parsers/parsers.a - -all: stm32flash - -serial_platform.o: serial_posix.c serial_w32.c - -parsers/parsers.a: - cd parsers && $(MAKE) parsers.a - -stm32flash: $(OBJS) $(LIBOBJS) - $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBOBJS) - -clean: - rm -f $(OBJS) stm32flash - cd parsers && $(MAKE) $@ - -install: all - $(INSTALL) -d $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -m 755 stm32flash $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -d $(DESTDIR)$(PREFIX)/share/man/man1 - $(INSTALL) -m 644 stm32flash.1 $(DESTDIR)$(PREFIX)/share/man/man1 - -.PHONY: all clean install diff --git a/macosx/src/stm32flash_serial/src/TODO b/macosx/src/stm32flash_serial/src/TODO deleted file mode 100644 index 41df614ff..000000000 --- a/macosx/src/stm32flash_serial/src/TODO +++ /dev/null @@ -1,7 +0,0 @@ - -stm32: -- Add support for variable page size - -AUTHORS: -- Add contributors from Geoffrey's commits - diff --git a/macosx/src/stm32flash_serial/src/dev_table.c b/macosx/src/stm32flash_serial/src/dev_table.c deleted file mode 100644 index 399cd9d08..000000000 --- a/macosx/src/stm32flash_serial/src/dev_table.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "stm32.h" - -/* - * Device table, corresponds to the "Bootloader device-dependant parameters" - * table in ST document AN2606. - * Note that the option bytes upper range is inclusive! - */ -const stm32_dev_t devices[] = { - /* F0 */ - {0x440, "STM32F051xx" , 0x20001000, 0x20002000, 0x08000000, 0x08010000, 4, 1024, 0x1FFFF800, 0x1FFFF80B, 0x1FFFEC00, 0x1FFFF800}, - {0x444, "STM32F030/F031" , 0x20001000, 0x20002000, 0x08000000, 0x08010000, 4, 1024, 0x1FFFF800, 0x1FFFF80B, 0x1FFFEC00, 0x1FFFF800}, - {0x445, "STM32F042xx" , 0x20001800, 0x20001800, 0x08000000, 0x08008000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFC400, 0x1FFFF800}, - {0x448, "STM32F072xx" , 0x20001800, 0x20004000, 0x08000000, 0x08020000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFC800, 0x1FFFF800}, - /* F1 */ - {0x412, "Low-density" , 0x20000200, 0x20002800, 0x08000000, 0x08008000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x410, "Medium-density" , 0x20000200, 0x20005000, 0x08000000, 0x08020000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x414, "High-density" , 0x20000200, 0x20010000, 0x08000000, 0x08080000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x420, "Medium-density VL" , 0x20000200, 0x20002000, 0x08000000, 0x08020000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x428, "High-density VL" , 0x20000200, 0x20008000, 0x08000000, 0x08080000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x418, "Connectivity line" , 0x20001000, 0x20010000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFB000, 0x1FFFF800}, - {0x430, "XL-density" , 0x20000800, 0x20018000, 0x08000000, 0x08100000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFE000, 0x1FFFF800}, - /* Note that F2 and F4 devices have sectors of different page sizes - and only the first sectors (of one page size) are included here */ - /* F2 */ - {0x411, "STM32F2xx" , 0x20002000, 0x20020000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77DF}, - /* F3 */ - {0x432, "STM32F373/8" , 0x20001400, 0x20008000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - {0x422, "F302xB/303xB/358" , 0x20001400, 0x20010000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - {0x439, "STM32F302x4(6/8)" , 0x20001800, 0x20004000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - {0x438, "F303x4/334/328" , 0x20001800, 0x20003000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - /* F4 */ - {0x413, "STM32F40/1" , 0x20002000, 0x20020000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77DF}, - /* 0x419 is also used for STM32F429/39 but with other bootloader ID... */ - {0x419, "STM32F427/37" , 0x20002000, 0x20030000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF}, - {0x423, "STM32F401xB(C)" , 0x20003000, 0x20010000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF}, - {0x433, "STM32F401xD(E)" , 0x20003000, 0x20018000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF}, - /* L0 */ - {0x417, "L05xxx/06xxx" , 0x20001000, 0x20002000, 0x08000000, 0x08010000, 32, 128, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000}, - /* L1 */ - {0x416, "L1xxx6(8/B)" , 0x20000800, 0x20004000, 0x08000000, 0x08020000, 16, 256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000}, - {0x429, "L1xxx6(8/B)A" , 0x20001000, 0x20008000, 0x08000000, 0x08020000, 16, 256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000}, - {0x427, "L1xxxC" , 0x20001000, 0x20008000, 0x08000000, 0x08020000, 16, 256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF02000}, - {0x436, "L1xxxD" , 0x20001000, 0x2000C000, 0x08000000, 0x08060000, 16, 256, 0x1ff80000, 0x1ff8000F, 0x1FF00000, 0x1FF02000}, - {0x437, "L1xxxE" , 0x20001000, 0x20014000, 0x08000000, 0x08060000, 16, 256, 0x1ff80000, 0x1ff8000F, 0x1FF00000, 0x1FF02000}, - /* These are not (yet) in AN2606: */ - {0x641, "Medium_Density PL" , 0x20000200, 0x00005000, 0x08000000, 0x08020000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x9a8, "STM32W-128K" , 0x20000200, 0x20002000, 0x08000000, 0x08020000, 1, 1024, 0, 0, 0, 0}, - {0x9b0, "STM32W-256K" , 0x20000200, 0x20004000, 0x08000000, 0x08040000, 1, 2048, 0, 0, 0, 0}, - {0x0} -}; diff --git a/macosx/src/stm32flash_serial/src/gpl-2.0.txt b/macosx/src/stm32flash_serial/src/gpl-2.0.txt deleted file mode 100644 index d159169d1..000000000 --- a/macosx/src/stm32flash_serial/src/gpl-2.0.txt +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 2 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, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/macosx/src/stm32flash_serial/src/i2c.c b/macosx/src/stm32flash_serial/src/i2c.c deleted file mode 100644 index 10e6bb15a..000000000 --- a/macosx/src/stm32flash_serial/src/i2c.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "serial.h" -#include "port.h" - - -#if !defined(__linux__) - -static port_err_t i2c_open(struct port_interface *port, - struct port_options *ops) -{ - return PORT_ERR_NODEV; -} - -struct port_interface port_i2c = { - .name = "i2c", - .open = i2c_open, -}; - -#else - -#ifdef __ANDROID__ -#define I2C_SLAVE 0x0703 /* Use this slave address */ -#define I2C_FUNCS 0x0705 /* Get the adapter functionality mask */ -/* To determine what functionality is present */ -#define I2C_FUNC_I2C 0x00000001 -#else -#include -#include -#endif - -#include - -struct i2c_priv { - int fd; - int addr; -}; - -static port_err_t i2c_open(struct port_interface *port, - struct port_options *ops) -{ - struct i2c_priv *h; - int fd, addr, ret; - unsigned long funcs; - - /* 1. check device name match */ - if (strncmp(ops->device, "/dev/i2c-", strlen("/dev/i2c-"))) - return PORT_ERR_NODEV; - - /* 2. check options */ - addr = ops->bus_addr; - if (addr < 0x03 || addr > 0x77) { - fprintf(stderr, "I2C address out of range [0x03-0x77]\n"); - return PORT_ERR_UNKNOWN; - } - - /* 3. open it */ - h = calloc(sizeof(*h), 1); - if (h == NULL) { - fprintf(stderr, "End of memory\n"); - return PORT_ERR_UNKNOWN; - } - fd = open(ops->device, O_RDWR); - if (fd < 0) { - fprintf(stderr, "Unable to open special file \"%s\"\n", - ops->device); - free(h); - return PORT_ERR_UNKNOWN; - } - - /* 3.5. Check capabilities */ - ret = ioctl(fd, I2C_FUNCS, &funcs); - if (ret < 0) { - fprintf(stderr, "I2C ioctl(funcs) error %d\n", errno); - close(fd); - free(h); - return PORT_ERR_UNKNOWN; - } - if ((funcs & I2C_FUNC_I2C) == 0) { - fprintf(stderr, "Error: controller is not I2C, only SMBUS.\n"); - close(fd); - free(h); - return PORT_ERR_UNKNOWN; - } - - /* 4. set options */ - ret = ioctl(fd, I2C_SLAVE, addr); - if (ret < 0) { - fprintf(stderr, "I2C ioctl(slave) error %d\n", errno); - close(fd); - free(h); - return PORT_ERR_UNKNOWN; - } - - h->fd = fd; - h->addr = addr; - port->private = h; - return PORT_ERR_OK; -} - -static port_err_t i2c_close(struct port_interface *port) -{ - struct i2c_priv *h; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - close(h->fd); - free(h); - port->private = NULL; - return PORT_ERR_OK; -} - -static port_err_t i2c_read(struct port_interface *port, void *buf, - size_t nbyte) -{ - struct i2c_priv *h; - int ret; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - ret = read(h->fd, buf, nbyte); - if (ret != nbyte) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; -} - -static port_err_t i2c_write(struct port_interface *port, void *buf, - size_t nbyte) -{ - struct i2c_priv *h; - int ret; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - ret = write(h->fd, buf, nbyte); - if (ret != nbyte) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; -} - -static port_err_t i2c_gpio(struct port_interface *port, serial_gpio_t n, - int level) -{ - return PORT_ERR_OK; -} - -static const char *i2c_get_cfg_str(struct port_interface *port) -{ - struct i2c_priv *h; - static char str[11]; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return "INVALID"; - snprintf(str, sizeof(str), "addr 0x%2x", h->addr); - return str; -} - -static struct varlen_cmd i2c_cmd_get_reply[] = { - {0x10, 11}, - {0x11, 17}, - {0x12, 18}, - { /* sentinel */ } -}; - -struct port_interface port_i2c = { - .name = "i2c", - .flags = PORT_STRETCH_W, - .open = i2c_open, - .close = i2c_close, - .read = i2c_read, - .write = i2c_write, - .gpio = i2c_gpio, - .cmd_get_reply = i2c_cmd_get_reply, - .get_cfg_str = i2c_get_cfg_str, -}; - -#endif diff --git a/macosx/src/stm32flash_serial/src/init.c b/macosx/src/stm32flash_serial/src/init.c deleted file mode 100644 index 77a571bd8..000000000 --- a/macosx/src/stm32flash_serial/src/init.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2013 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "init.h" -#include "serial.h" -#include "stm32.h" -#include "port.h" - -struct gpio_list { - struct gpio_list *next; - int gpio; -}; - - -static int write_to(const char *filename, const char *value) -{ - int fd, ret; - - fd = open(filename, O_WRONLY); - if (fd < 0) { - fprintf(stderr, "Cannot open file \"%s\"\n", filename); - return 0; - } - ret = write(fd, value, strlen(value)); - if (ret < 0) { - fprintf(stderr, "Error writing in file \"%s\"\n", filename); - close(fd); - return 0; - } - close(fd); - return 1; -} - -#if !defined(__linux__) -static int drive_gpio(int n, int level, struct gpio_list **gpio_to_release) -{ - fprintf(stderr, "GPIO control only available in Linux\n"); - return 0; -} -#else -static int drive_gpio(int n, int level, struct gpio_list **gpio_to_release) -{ - char num[16]; /* sized to carry MAX_INT */ - char file[48]; /* sized to carry longest filename */ - struct stat buf; - struct gpio_list *new; - int ret; - - sprintf(file, "/sys/class/gpio/gpio%d/direction", n); - ret = stat(file, &buf); - if (ret) { - /* file miss, GPIO not exported yet */ - sprintf(num, "%d", n); - ret = write_to("/sys/class/gpio/export", num); - if (!ret) - return 0; - ret = stat(file, &buf); - if (ret) { - fprintf(stderr, "GPIO %d not available\n", n); - return 0; - } - new = (struct gpio_list *)malloc(sizeof(struct gpio_list)); - if (new == NULL) { - fprintf(stderr, "Out of memory\n"); - return 0; - } - new->gpio = n; - new->next = *gpio_to_release; - *gpio_to_release = new; - } - - return write_to(file, level ? "high" : "low"); -} -#endif - -static int release_gpio(int n) -{ - char num[16]; /* sized to carry MAX_INT */ - - sprintf(num, "%d", n); - return write_to("/sys/class/gpio/unexport", num); -} - -static int gpio_sequence(struct port_interface *port, const char *s, size_t l) -{ - struct gpio_list *gpio_to_release = NULL, *to_free; - int ret, level, gpio; - - ret = 1; - while (ret == 1 && *s && l > 0) { - if (*s == '-') { - level = 0; - s++; - l--; - } else - level = 1; - - if (isdigit(*s)) { - gpio = atoi(s); - while (isdigit(*s)) { - s++; - l--; - } - } else if (!strncmp(s, "rts", 3)) { - gpio = -GPIO_RTS; - s += 3; - l -= 3; - } else if (!strncmp(s, "dtr", 3)) { - gpio = -GPIO_DTR; - s += 3; - l -= 3; - } else if (!strncmp(s, "brk", 3)) { - gpio = -GPIO_BRK; - s += 3; - l -= 3; - } else { - fprintf(stderr, "Character \'%c\' is not a digit\n", *s); - ret = 0; - break; - } - - if (*s && (l > 0)) { - if (*s == ',') { - s++; - l--; - } else { - fprintf(stderr, "Character \'%c\' is not a separator\n", *s); - ret = 0; - break; - } - } - if (gpio < 0) - ret = (port->gpio(port, -gpio, level) == PORT_ERR_OK); - else - ret = drive_gpio(gpio, level, &gpio_to_release); - usleep(100000); - } - - while (gpio_to_release) { - release_gpio(gpio_to_release->gpio); - to_free = gpio_to_release; - gpio_to_release = gpio_to_release->next; - free(to_free); - } - usleep(500000); - return ret; -} - -static int gpio_bl_entry(struct port_interface *port, const char *seq) -{ - char *s; - - if (seq == NULL || seq[0] == ':') - return 1; - - s = strchr(seq, ':'); - if (s == NULL) - return gpio_sequence(port, seq, strlen(seq)); - - return gpio_sequence(port, seq, s - seq); -} - -static int gpio_bl_exit(struct port_interface *port, const char *seq) -{ - char *s; - - if (seq == NULL) - return 1; - - s = strchr(seq, ':'); - if (s == NULL || s[1] == '\0') - return 1; - - return gpio_sequence(port, s + 1, strlen(s + 1)); -} - -int init_bl_entry(struct port_interface *port, const char *seq) -{ - if (seq) - return gpio_bl_entry(port, seq); - - return 1; -} - -int init_bl_exit(stm32_t *stm, struct port_interface *port, const char *seq) -{ - if (seq) - return gpio_bl_exit(port, seq); - - if (stm32_reset_device(stm) != STM32_ERR_OK) - return 0; - return 1; -} diff --git a/macosx/src/stm32flash_serial/src/init.h b/macosx/src/stm32flash_serial/src/init.h deleted file mode 100644 index 6075b519b..000000000 --- a/macosx/src/stm32flash_serial/src/init.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2013 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _INIT_H -#define _INIT_H - -#include "stm32.h" -#include "port.h" - -int init_bl_entry(struct port_interface *port, const char *seq); -int init_bl_exit(stm32_t *stm, struct port_interface *port, const char *seq); - -#endif diff --git a/macosx/src/stm32flash_serial/src/main.c b/macosx/src/stm32flash_serial/src/main.c deleted file mode 100644 index f081d6131..000000000 --- a/macosx/src/stm32flash_serial/src/main.c +++ /dev/null @@ -1,774 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright 2010 Geoffrey McRae - Copyright 2011 Steve Markgraf - Copyright 2012 Tormod Volden - Copyright 2013 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "init.h" -#include "utils.h" -#include "serial.h" -#include "stm32.h" -#include "parsers/parser.h" -#include "port.h" - -#include "parsers/binary.h" -#include "parsers/hex.h" - -#define VERSION "Arduino_STM32_0.9" - -/* device globals */ -stm32_t *stm = NULL; - -void *p_st = NULL; -parser_t *parser = NULL; - -/* settings */ -struct port_options port_opts = { - .device = NULL, - .baudRate = SERIAL_BAUD_57600, - .serial_mode = "8e1", - .bus_addr = 0, - .rx_frame_max = STM32_MAX_RX_FRAME, - .tx_frame_max = STM32_MAX_TX_FRAME, -}; -int rd = 0; -int wr = 0; -int wu = 0; -int rp = 0; -int ur = 0; -int eraseOnly = 0; -int crc = 0; -int npages = 0; -int spage = 0; -int no_erase = 0; -char verify = 0; -int retry = 10; -char exec_flag = 0; -uint32_t execute = 0; -char init_flag = 1; -char force_binary = 0; -char reset_flag = 0; -char *filename; -char *gpio_seq = NULL; -uint32_t start_addr = 0; -uint32_t readwrite_len = 0; - -/* functions */ -int parse_options(int argc, char *argv[]); -void show_help(char *name); - -static int is_addr_in_ram(uint32_t addr) -{ - return addr >= stm->dev->ram_start && addr < stm->dev->ram_end; -} - -static int is_addr_in_flash(uint32_t addr) -{ - return addr >= stm->dev->fl_start && addr < stm->dev->fl_end; -} - -static int flash_addr_to_page_floor(uint32_t addr) -{ - if (!is_addr_in_flash(addr)) - return 0; - - return (addr - stm->dev->fl_start) / stm->dev->fl_ps; -} - -static int flash_addr_to_page_ceil(uint32_t addr) -{ - if (!(addr >= stm->dev->fl_start && addr <= stm->dev->fl_end)) - return 0; - - return (addr + stm->dev->fl_ps - 1 - stm->dev->fl_start) - / stm->dev->fl_ps; -} - -static uint32_t flash_page_to_addr(int page) -{ - return stm->dev->fl_start + page * stm->dev->fl_ps; -} - -int main(int argc, char* argv[]) { - struct port_interface *port = NULL; - int ret = 1; - stm32_err_t s_err; - parser_err_t perr; - FILE *diag = stdout; - - fprintf(diag, "stm32flash " VERSION "\n\n"); - fprintf(diag, "http://github.com/rogerclarkmelbourne/arduino_stm32\n\n"); - if (parse_options(argc, argv) != 0) - goto close; - - if (rd && filename[0] == '-') { - diag = stderr; - } - - if (wr) { - /* first try hex */ - if (!force_binary) { - parser = &PARSER_HEX; - p_st = parser->init(); - if (!p_st) { - fprintf(stderr, "%s Parser failed to initialize\n", parser->name); - goto close; - } - } - - if (force_binary || (perr = parser->open(p_st, filename, 0)) != PARSER_ERR_OK) { - if (force_binary || perr == PARSER_ERR_INVALID_FILE) { - if (!force_binary) { - parser->close(p_st); - p_st = NULL; - } - - /* now try binary */ - parser = &PARSER_BINARY; - p_st = parser->init(); - if (!p_st) { - fprintf(stderr, "%s Parser failed to initialize\n", parser->name); - goto close; - } - perr = parser->open(p_st, filename, 0); - } - - /* if still have an error, fail */ - if (perr != PARSER_ERR_OK) { - fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr)); - if (perr == PARSER_ERR_SYSTEM) perror(filename); - goto close; - } - } - - fprintf(diag, "Using Parser : %s\n", parser->name); - } else { - parser = &PARSER_BINARY; - p_st = parser->init(); - if (!p_st) { - fprintf(stderr, "%s Parser failed to initialize\n", parser->name); - goto close; - } - } - - if (port_open(&port_opts, &port) != PORT_ERR_OK) { - fprintf(stderr, "Failed to open port: %s\n", port_opts.device); - goto close; - } - - fprintf(diag, "Interface %s: %s\n", port->name, port->get_cfg_str(port)); - if (init_flag && init_bl_entry(port, gpio_seq) == 0) - goto close; - stm = stm32_init(port, init_flag); - if (!stm) - goto close; - - fprintf(diag, "Version : 0x%02x\n", stm->bl_version); - if (port->flags & PORT_GVR_ETX) { - fprintf(diag, "Option 1 : 0x%02x\n", stm->option1); - fprintf(diag, "Option 2 : 0x%02x\n", stm->option2); - } - fprintf(diag, "Device ID : 0x%04x (%s)\n", stm->pid, stm->dev->name); - fprintf(diag, "- RAM : %dKiB (%db reserved by bootloader)\n", (stm->dev->ram_end - 0x20000000) / 1024, stm->dev->ram_start - 0x20000000); - fprintf(diag, "- Flash : %dKiB (sector size: %dx%d)\n", (stm->dev->fl_end - stm->dev->fl_start ) / 1024, stm->dev->fl_pps, stm->dev->fl_ps); - fprintf(diag, "- Option RAM : %db\n", stm->dev->opt_end - stm->dev->opt_start + 1); - fprintf(diag, "- System RAM : %dKiB\n", (stm->dev->mem_end - stm->dev->mem_start) / 1024); - - uint8_t buffer[256]; - uint32_t addr, start, end; - unsigned int len; - int failed = 0; - int first_page, num_pages; - - /* - * Cleanup addresses: - * - * Starting from options - * start_addr, readwrite_len, spage, npages - * and using device memory size, compute - * start, end, first_page, num_pages - */ - if (start_addr || readwrite_len) { - start = start_addr; - - if (is_addr_in_flash(start)) - end = stm->dev->fl_end; - else { - no_erase = 1; - if (is_addr_in_ram(start)) - end = stm->dev->ram_end; - else - end = start + sizeof(uint32_t); - } - - if (readwrite_len && (end > start + readwrite_len)) - end = start + readwrite_len; - - first_page = flash_addr_to_page_floor(start); - if (!first_page && end == stm->dev->fl_end) - num_pages = 0xff; /* mass erase */ - else - num_pages = flash_addr_to_page_ceil(end) - first_page; - } else if (!spage && !npages) { - start = stm->dev->fl_start; - end = stm->dev->fl_end; - first_page = 0; - num_pages = 0xff; /* mass erase */ - } else { - first_page = spage; - start = flash_page_to_addr(first_page); - if (start > stm->dev->fl_end) { - fprintf(stderr, "Address range exceeds flash size.\n"); - goto close; - } - - if (npages) { - num_pages = npages; - end = flash_page_to_addr(first_page + num_pages); - if (end > stm->dev->fl_end) - end = stm->dev->fl_end; - } else { - end = stm->dev->fl_end; - num_pages = flash_addr_to_page_ceil(end) - first_page; - } - - if (!first_page && end == stm->dev->fl_end) - num_pages = 0xff; /* mass erase */ - } - - if (rd) { - unsigned int max_len = port_opts.rx_frame_max; - - fprintf(diag, "Memory read\n"); - - perr = parser->open(p_st, filename, 1); - if (perr != PARSER_ERR_OK) { - fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr)); - if (perr == PARSER_ERR_SYSTEM) - perror(filename); - goto close; - } - - fflush(diag); - addr = start; - while(addr < end) { - uint32_t left = end - addr; - len = max_len > left ? left : max_len; - s_err = stm32_read_memory(stm, addr, buffer, len); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to read memory at address 0x%08x, target write-protected?\n", addr); - goto close; - } - if (parser->write(p_st, buffer, len) != PARSER_ERR_OK) - { - fprintf(stderr, "Failed to write data to file\n"); - goto close; - } - addr += len; - - fprintf(diag, - "\rRead address 0x%08x (%.2f%%) ", - addr, - (100.0f / (float)(end - start)) * (float)(addr - start) - ); - fflush(diag); - } - fprintf(diag, "Done.\n"); - ret = 0; - goto close; - } else if (rp) { - fprintf(stdout, "Read-Protecting flash\n"); - /* the device automatically performs a reset after the sending the ACK */ - reset_flag = 0; - stm32_readprot_memory(stm); - fprintf(stdout, "Done.\n"); - } else if (ur) { - fprintf(stdout, "Read-UnProtecting flash\n"); - /* the device automatically performs a reset after the sending the ACK */ - reset_flag = 0; - stm32_runprot_memory(stm); - fprintf(stdout, "Done.\n"); - } else if (eraseOnly) { - ret = 0; - fprintf(stdout, "Erasing flash\n"); - - if (num_pages != 0xff && - (start != flash_page_to_addr(first_page) - || end != flash_page_to_addr(first_page + num_pages))) { - fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n"); - ret = 1; - goto close; - } - - s_err = stm32_erase_memory(stm, first_page, num_pages); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to erase memory\n"); - ret = 1; - goto close; - } - } else if (wu) { - fprintf(diag, "Write-unprotecting flash\n"); - /* the device automatically performs a reset after the sending the ACK */ - reset_flag = 0; - stm32_wunprot_memory(stm); - fprintf(diag, "Done.\n"); - - } else if (wr) { - fprintf(diag, "Write to memory\n"); - - off_t offset = 0; - ssize_t r; - unsigned int size; - unsigned int max_wlen, max_rlen; - - max_wlen = port_opts.tx_frame_max - 2; /* skip len and crc */ - max_wlen &= ~3; /* 32 bit aligned */ - - max_rlen = port_opts.rx_frame_max; - max_rlen = max_rlen < max_wlen ? max_rlen : max_wlen; - - /* Assume data from stdin is whole device */ - if (filename[0] == '-' && filename[1] == '\0') - size = end - start; - else - size = parser->size(p_st); - - // TODO: It is possible to write to non-page boundaries, by reading out flash - // from partial pages and combining with the input data - // if ((start % stm->dev->fl_ps) != 0 || (end % stm->dev->fl_ps) != 0) { - // fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n"); - // goto close; - // } - - // TODO: If writes are not page aligned, we should probably read out existing flash - // contents first, so it can be preserved and combined with new data - if (!no_erase && num_pages) { - fprintf(diag, "Erasing memory\n"); - s_err = stm32_erase_memory(stm, first_page, num_pages); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to erase memory\n"); - goto close; - } - } - - fflush(diag); - addr = start; - while(addr < end && offset < size) { - uint32_t left = end - addr; - len = max_wlen > left ? left : max_wlen; - len = len > size - offset ? size - offset : len; - - if (parser->read(p_st, buffer, &len) != PARSER_ERR_OK) - goto close; - - if (len == 0) { - if (filename[0] == '-') { - break; - } else { - fprintf(stderr, "Failed to read input file\n"); - goto close; - } - } - - again: - s_err = stm32_write_memory(stm, addr, buffer, len); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to write memory at address 0x%08x\n", addr); - goto close; - } - - if (verify) { - uint8_t compare[len]; - unsigned int offset, rlen; - - offset = 0; - while (offset < len) { - rlen = len - offset; - rlen = rlen < max_rlen ? rlen : max_rlen; - s_err = stm32_read_memory(stm, addr + offset, compare + offset, rlen); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to read memory at address 0x%08x\n", addr + offset); - goto close; - } - offset += rlen; - } - - for(r = 0; r < len; ++r) - if (buffer[r] != compare[r]) { - if (failed == retry) { - fprintf(stderr, "Failed to verify at address 0x%08x, expected 0x%02x and found 0x%02x\n", - (uint32_t)(addr + r), - buffer [r], - compare[r] - ); - goto close; - } - ++failed; - goto again; - } - - failed = 0; - } - - addr += len; - offset += len; - - fprintf(diag, - "\rWrote %saddress 0x%08x (%.2f%%) ", - verify ? "and verified " : "", - addr, - (100.0f / size) * offset - ); - fflush(diag); - - } - - fprintf(diag, "Done.\n"); - ret = 0; - goto close; - } else if (crc) { - uint32_t crc_val = 0; - - fprintf(diag, "CRC computation\n"); - - s_err = stm32_crc_wrapper(stm, start, end - start, &crc_val); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to read CRC\n"); - goto close; - } - fprintf(diag, "CRC(0x%08x-0x%08x) = 0x%08x\n", start, end, - crc_val); - ret = 0; - goto close; - } else - ret = 0; - -close: - if (stm && exec_flag && ret == 0) { - if (execute == 0) - execute = stm->dev->fl_start; - - fprintf(diag, "\nStarting execution at address 0x%08x... ", execute); - fflush(diag); - if (stm32_go(stm, execute) == STM32_ERR_OK) { - reset_flag = 0; - fprintf(diag, "done.\n"); - } else - fprintf(diag, "failed.\n"); - } - - if (stm && reset_flag) { - fprintf(diag, "\nResetting device... "); - fflush(diag); - if (init_bl_exit(stm, port, gpio_seq)) - fprintf(diag, "done.\n"); - else fprintf(diag, "failed.\n"); - } - - if (p_st ) parser->close(p_st); - if (stm ) stm32_close (stm); - if (port) - port->close(port); - - fprintf(diag, "\n"); - return ret; -} - -int parse_options(int argc, char *argv[]) -{ - int c; - char *pLen; - - while ((c = getopt(argc, argv, "a:b:m:r:w:e:vn:g:jkfcChuos:S:F:i:R")) != -1) { - switch(c) { - case 'a': - port_opts.bus_addr = strtoul(optarg, NULL, 0); - break; - - case 'b': - port_opts.baudRate = serial_get_baud(strtoul(optarg, NULL, 0)); - if (port_opts.baudRate == SERIAL_BAUD_INVALID) { - serial_baud_t baudrate; - fprintf(stderr, "Invalid baud rate, valid options are:\n"); - for (baudrate = SERIAL_BAUD_1200; baudrate != SERIAL_BAUD_INVALID; ++baudrate) - fprintf(stderr, " %d\n", serial_get_baud_int(baudrate)); - return 1; - } - break; - - case 'm': - if (strlen(optarg) != 3 - || serial_get_bits(optarg) == SERIAL_BITS_INVALID - || serial_get_parity(optarg) == SERIAL_PARITY_INVALID - || serial_get_stopbit(optarg) == SERIAL_STOPBIT_INVALID) { - fprintf(stderr, "Invalid serial mode\n"); - return 1; - } - port_opts.serial_mode = optarg; - break; - - case 'r': - case 'w': - rd = rd || c == 'r'; - wr = wr || c == 'w'; - if (rd && wr) { - fprintf(stderr, "ERROR: Invalid options, can't read & write at the same time\n"); - return 1; - } - filename = optarg; - if (filename[0] == '-') { - force_binary = 1; - } - break; - case 'e': - if (readwrite_len || start_addr) { - fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n"); - return 1; - } - npages = strtoul(optarg, NULL, 0); - if (npages > 0xFF || npages < 0) { - fprintf(stderr, "ERROR: You need to specify a page count between 0 and 255"); - return 1; - } - if (!npages) - no_erase = 1; - break; - case 'u': - wu = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't write unprotect and read/write at the same time\n"); - return 1; - } - break; - - case 'j': - rp = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't read protect and read/write at the same time\n"); - return 1; - } - break; - - case 'k': - ur = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't read unprotect and read/write at the same time\n"); - return 1; - } - break; - - case 'o': - eraseOnly = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't erase-only and read/write at the same time\n"); - return 1; - } - break; - - case 'v': - verify = 1; - break; - - case 'n': - retry = strtoul(optarg, NULL, 0); - break; - - case 'g': - exec_flag = 1; - execute = strtoul(optarg, NULL, 0); - if (execute % 4 != 0) { - fprintf(stderr, "ERROR: Execution address must be word-aligned\n"); - return 1; - } - break; - case 's': - if (readwrite_len || start_addr) { - fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n"); - return 1; - } - spage = strtoul(optarg, NULL, 0); - break; - case 'S': - if (spage || npages) { - fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n"); - return 1; - } else { - start_addr = strtoul(optarg, &pLen, 0); - if (*pLen == ':') { - pLen++; - readwrite_len = strtoul(pLen, NULL, 0); - if (readwrite_len == 0) { - fprintf(stderr, "ERROR: Invalid options, can't specify zero length\n"); - return 1; - } - } - } - break; - case 'F': - port_opts.rx_frame_max = strtoul(optarg, &pLen, 0); - if (*pLen == ':') { - pLen++; - port_opts.tx_frame_max = strtoul(pLen, NULL, 0); - } - if (port_opts.rx_frame_max < 0 - || port_opts.tx_frame_max < 0) { - fprintf(stderr, "ERROR: Invalid negative value for option -F\n"); - return 1; - } - if (port_opts.rx_frame_max == 0) - port_opts.rx_frame_max = STM32_MAX_RX_FRAME; - if (port_opts.tx_frame_max == 0) - port_opts.tx_frame_max = STM32_MAX_TX_FRAME; - if (port_opts.rx_frame_max < 20 - || port_opts.tx_frame_max < 5) { - fprintf(stderr, "ERROR: current code cannot work with small frames.\n"); - fprintf(stderr, "min(RX) = 20, min(TX) = 5\n"); - return 1; - } - if (port_opts.rx_frame_max > STM32_MAX_RX_FRAME) { - fprintf(stderr, "WARNING: Ignore RX length in option -F\n"); - port_opts.rx_frame_max = STM32_MAX_RX_FRAME; - } - if (port_opts.tx_frame_max > STM32_MAX_TX_FRAME) { - fprintf(stderr, "WARNING: Ignore TX length in option -F\n"); - port_opts.tx_frame_max = STM32_MAX_TX_FRAME; - } - break; - case 'f': - force_binary = 1; - break; - - case 'c': - init_flag = 0; - break; - - case 'h': - show_help(argv[0]); - exit(0); - - case 'i': - gpio_seq = optarg; - break; - - case 'R': - reset_flag = 1; - break; - - case 'C': - crc = 1; - break; - } - } - - for (c = optind; c < argc; ++c) { - if (port_opts.device) { - fprintf(stderr, "ERROR: Invalid parameter specified\n"); - show_help(argv[0]); - return 1; - } - port_opts.device = argv[c]; - } - - if (port_opts.device == NULL) { - fprintf(stderr, "ERROR: Device not specified\n"); - show_help(argv[0]); - return 1; - } - - if (!wr && verify) { - fprintf(stderr, "ERROR: Invalid usage, -v is only valid when writing\n"); - show_help(argv[0]); - return 1; - } - - return 0; -} - -void show_help(char *name) { - fprintf(stderr, - "Usage: %s [-bvngfhc] [-[rw] filename] [tty_device | i2c_device]\n" - " -a bus_address Bus address (e.g. for I2C port)\n" - " -b rate Baud rate (default 57600)\n" - " -m mode Serial port mode (default 8e1)\n" - " -r filename Read flash to file (or - stdout)\n" - " -w filename Write flash from file (or - stdout)\n" - " -C Compute CRC of flash content\n" - " -u Disable the flash write-protection\n" - " -j Enable the flash read-protection\n" - " -k Disable the flash read-protection\n" - " -o Erase only\n" - " -e n Only erase n pages before writing the flash\n" - " -v Verify writes\n" - " -n count Retry failed writes up to count times (default 10)\n" - " -g address Start execution at specified address (0 = flash start)\n" - " -S address[:length] Specify start address and optionally length for\n" - " read/write/erase operations\n" - " -F RX_length[:TX_length] Specify the max length of RX and TX frame\n" - " -s start_page Flash at specified page (0 = flash start)\n" - " -f Force binary parser\n" - " -h Show this help\n" - " -c Resume the connection (don't send initial INIT)\n" - " *Baud rate must be kept the same as the first init*\n" - " This is useful if the reset fails\n" - " -i GPIO_string GPIO sequence to enter/exit bootloader mode\n" - " GPIO_string=[entry_seq][:[exit_seq]]\n" - " sequence=[-]n[,sequence]\n" - " -R Reset device at exit.\n" - "\n" - "Examples:\n" - " Get device information:\n" - " %s /dev/ttyS0\n" - " or:\n" - " %s /dev/i2c-0\n" - "\n" - " Write with verify and then start execution:\n" - " %s -w filename -v -g 0x0 /dev/ttyS0\n" - "\n" - " Read flash to file:\n" - " %s -r filename /dev/ttyS0\n" - "\n" - " Read 100 bytes of flash from 0x1000 to stdout:\n" - " %s -r - -S 0x1000:100 /dev/ttyS0\n" - "\n" - " Start execution:\n" - " %s -g 0x0 /dev/ttyS0\n" - "\n" - " GPIO sequence:\n" - " - entry sequence: GPIO_3=low, GPIO_2=low, GPIO_2=high\n" - " - exit sequence: GPIO_3=high, GPIO_2=low, GPIO_2=high\n" - " %s -i -3,-2,2:3,-2,2 /dev/ttyS0\n", - name, - name, - name, - name, - name, - name, - name, - name - ); -} - diff --git a/macosx/src/stm32flash_serial/src/parsers/Android.mk b/macosx/src/stm32flash_serial/src/parsers/Android.mk deleted file mode 100644 index afec18cd5..000000000 --- a/macosx/src/stm32flash_serial/src/parsers/Android.mk +++ /dev/null @@ -1,6 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := libparsers -LOCAL_SRC_FILES := binary.c hex.c -include $(BUILD_STATIC_LIBRARY) diff --git a/macosx/src/stm32flash_serial/src/parsers/Makefile b/macosx/src/stm32flash_serial/src/parsers/Makefile deleted file mode 100644 index bb7df1e02..000000000 --- a/macosx/src/stm32flash_serial/src/parsers/Makefile +++ /dev/null @@ -1,12 +0,0 @@ - -CFLAGS += -Wall -g - -all: parsers.a - -parsers.a: binary.o hex.o - $(AR) rc $@ binary.o hex.o - -clean: - rm -f *.o parsers.a - -.PHONY: all clean diff --git a/macosx/src/stm32flash_serial/src/parsers/binary.c b/macosx/src/stm32flash_serial/src/parsers/binary.c deleted file mode 100644 index f491952bb..000000000 --- a/macosx/src/stm32flash_serial/src/parsers/binary.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include - -#include "binary.h" - -typedef struct { - int fd; - char write; - struct stat stat; -} binary_t; - -void* binary_init() { - return calloc(sizeof(binary_t), 1); -} - -parser_err_t binary_open(void *storage, const char *filename, const char write) { - binary_t *st = storage; - if (write) { - if (filename[0] == '-') - st->fd = 1; - else - st->fd = open( - filename, -#ifndef __WIN32__ - O_WRONLY | O_CREAT | O_TRUNC, -#else - O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, -#endif -#ifndef __WIN32__ - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH -#else - 0 -#endif - ); - st->stat.st_size = 0; - } else { - if (filename[0] == '-') { - st->fd = 0; - } else { - if (stat(filename, &st->stat) != 0) - return PARSER_ERR_INVALID_FILE; - st->fd = open(filename, -#ifndef __WIN32__ - O_RDONLY -#else - O_RDONLY | O_BINARY -#endif - ); - } - } - - st->write = write; - return st->fd == -1 ? PARSER_ERR_SYSTEM : PARSER_ERR_OK; -} - -parser_err_t binary_close(void *storage) { - binary_t *st = storage; - - if (st->fd) close(st->fd); - free(st); - return PARSER_ERR_OK; -} - -unsigned int binary_size(void *storage) { - binary_t *st = storage; - return st->stat.st_size; -} - -parser_err_t binary_read(void *storage, void *data, unsigned int *len) { - binary_t *st = storage; - unsigned int left = *len; - if (st->write) return PARSER_ERR_WRONLY; - - ssize_t r; - while(left > 0) { - r = read(st->fd, data, left); - /* If there is no data to read at all, return OK, but with zero read */ - if (r == 0 && left == *len) { - *len = 0; - return PARSER_ERR_OK; - } - if (r <= 0) return PARSER_ERR_SYSTEM; - left -= r; - data += r; - } - - *len = *len - left; - return PARSER_ERR_OK; -} - -parser_err_t binary_write(void *storage, void *data, unsigned int len) { - binary_t *st = storage; - if (!st->write) return PARSER_ERR_RDONLY; - - ssize_t r; - while(len > 0) { - r = write(st->fd, data, len); - if (r < 1) return PARSER_ERR_SYSTEM; - st->stat.st_size += r; - - len -= r; - data += r; - } - - return PARSER_ERR_OK; -} - -parser_t PARSER_BINARY = { - "Raw BINARY", - binary_init, - binary_open, - binary_close, - binary_size, - binary_read, - binary_write -}; - diff --git a/macosx/src/stm32flash_serial/src/parsers/binary.h b/macosx/src/stm32flash_serial/src/parsers/binary.h deleted file mode 100644 index d989acfa0..000000000 --- a/macosx/src/stm32flash_serial/src/parsers/binary.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _PARSER_BINARY_H -#define _PARSER_BINARY_H - -#include "parser.h" - -extern parser_t PARSER_BINARY; -#endif diff --git a/macosx/src/stm32flash_serial/src/parsers/hex.c b/macosx/src/stm32flash_serial/src/parsers/hex.c deleted file mode 100644 index 3baf85623..000000000 --- a/macosx/src/stm32flash_serial/src/parsers/hex.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include - -#include "hex.h" -#include "../utils.h" - -typedef struct { - size_t data_len, offset; - uint8_t *data; - uint8_t base; -} hex_t; - -void* hex_init() { - return calloc(sizeof(hex_t), 1); -} - -parser_err_t hex_open(void *storage, const char *filename, const char write) { - hex_t *st = storage; - if (write) { - return PARSER_ERR_RDONLY; - } else { - char mark; - int i, fd; - uint8_t checksum; - unsigned int c; - uint32_t base = 0; - unsigned int last_address = 0x0; - - fd = open(filename, O_RDONLY); - if (fd < 0) - return PARSER_ERR_SYSTEM; - - /* read in the file */ - - while(read(fd, &mark, 1) != 0) { - if (mark == '\n' || mark == '\r') continue; - if (mark != ':') - return PARSER_ERR_INVALID_FILE; - - char buffer[9]; - unsigned int reclen, address, type; - uint8_t *record = NULL; - - /* get the reclen, address, and type */ - buffer[8] = 0; - if (read(fd, &buffer, 8) != 8) return PARSER_ERR_INVALID_FILE; - if (sscanf(buffer, "%2x%4x%2x", &reclen, &address, &type) != 3) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - /* setup the checksum */ - checksum = - reclen + - ((address & 0xFF00) >> 8) + - ((address & 0x00FF) >> 0) + - type; - - switch(type) { - /* data record */ - case 0: - c = address - last_address; - st->data = realloc(st->data, st->data_len + c + reclen); - - /* if there is a gap, set it to 0xff and increment the length */ - if (c > 0) { - memset(&st->data[st->data_len], 0xff, c); - st->data_len += c; - } - - last_address = address + reclen; - record = &st->data[st->data_len]; - st->data_len += reclen; - break; - - /* extended segment address record */ - case 2: - base = 0; - break; - - /* extended linear address record */ - case 4: - base = address; - break; - } - - buffer[2] = 0; - for(i = 0; i < reclen; ++i) { - if (read(fd, &buffer, 2) != 2 || sscanf(buffer, "%2x", &c) != 1) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - /* add the byte to the checksum */ - checksum += c; - - switch(type) { - case 0: - if (record != NULL) { - record[i] = c; - } else { - return PARSER_ERR_INVALID_FILE; - } - break; - - case 2: - case 4: - base = (base << 8) | c; - break; - } - } - - /* read, scan, and verify the checksum */ - if ( - read(fd, &buffer, 2 ) != 2 || - sscanf(buffer, "%2x", &c) != 1 || - (uint8_t)(checksum + c) != 0x00 - ) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - switch(type) { - /* EOF */ - case 1: - close(fd); - return PARSER_ERR_OK; - - /* address record */ - case 2: base = base << 4; - case 4: base = be_u32(base); - /* Reset last_address since our base changed */ - last_address = 0; - - if (st->base == 0) { - st->base = base; - break; - } - - /* we cant cope with files out of order */ - if (base < st->base) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - /* if there is a gap, enlarge and fill with zeros */ - unsigned int len = base - st->base; - if (len > st->data_len) { - st->data = realloc(st->data, len); - memset(&st->data[st->data_len], 0, len - st->data_len); - st->data_len = len; - } - break; - } - } - - close(fd); - return PARSER_ERR_OK; - } -} - -parser_err_t hex_close(void *storage) { - hex_t *st = storage; - if (st) free(st->data); - free(st); - return PARSER_ERR_OK; -} - -unsigned int hex_size(void *storage) { - hex_t *st = storage; - return st->data_len; -} - -parser_err_t hex_read(void *storage, void *data, unsigned int *len) { - hex_t *st = storage; - unsigned int left = st->data_len - st->offset; - unsigned int get = left > *len ? *len : left; - - memcpy(data, &st->data[st->offset], get); - st->offset += get; - - *len = get; - return PARSER_ERR_OK; -} - -parser_err_t hex_write(void *storage, void *data, unsigned int len) { - return PARSER_ERR_RDONLY; -} - -parser_t PARSER_HEX = { - "Intel HEX", - hex_init, - hex_open, - hex_close, - hex_size, - hex_read, - hex_write -}; - diff --git a/macosx/src/stm32flash_serial/src/parsers/hex.h b/macosx/src/stm32flash_serial/src/parsers/hex.h deleted file mode 100644 index 02413c9c9..000000000 --- a/macosx/src/stm32flash_serial/src/parsers/hex.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _PARSER_HEX_H -#define _PARSER_HEX_H - -#include "parser.h" - -extern parser_t PARSER_HEX; -#endif diff --git a/macosx/src/stm32flash_serial/src/parsers/parser.h b/macosx/src/stm32flash_serial/src/parsers/parser.h deleted file mode 100644 index c2fae3cf8..000000000 --- a/macosx/src/stm32flash_serial/src/parsers/parser.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _H_PARSER -#define _H_PARSER - -enum parser_err { - PARSER_ERR_OK, - PARSER_ERR_SYSTEM, - PARSER_ERR_INVALID_FILE, - PARSER_ERR_WRONLY, - PARSER_ERR_RDONLY -}; -typedef enum parser_err parser_err_t; - -struct parser { - const char *name; - void* (*init )(); /* initialise the parser */ - parser_err_t (*open )(void *storage, const char *filename, const char write); /* open the file for read|write */ - parser_err_t (*close)(void *storage); /* close and free the parser */ - unsigned int (*size )(void *storage); /* get the total data size */ - parser_err_t (*read )(void *storage, void *data, unsigned int *len); /* read a block of data */ - parser_err_t (*write)(void *storage, void *data, unsigned int len); /* write a block of data */ -}; -typedef struct parser parser_t; - -static inline const char* parser_errstr(parser_err_t err) { - switch(err) { - case PARSER_ERR_OK : return "OK"; - case PARSER_ERR_SYSTEM : return "System Error"; - case PARSER_ERR_INVALID_FILE: return "Invalid File"; - case PARSER_ERR_WRONLY : return "Parser can only write"; - case PARSER_ERR_RDONLY : return "Parser can only read"; - default: - return "Unknown Error"; - } -} - -#endif diff --git a/macosx/src/stm32flash_serial/src/port.c b/macosx/src/stm32flash_serial/src/port.c deleted file mode 100644 index 08e58cc34..000000000 --- a/macosx/src/stm32flash_serial/src/port.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include - -#include "serial.h" -#include "port.h" - - -extern struct port_interface port_serial; -extern struct port_interface port_i2c; - -static struct port_interface *ports[] = { - &port_serial, - &port_i2c, - NULL, -}; - - -port_err_t port_open(struct port_options *ops, struct port_interface **outport) -{ - int ret; - static struct port_interface **port; - - for (port = ports; *port; port++) { - ret = (*port)->open(*port, ops); - if (ret == PORT_ERR_NODEV) - continue; - if (ret == PORT_ERR_OK) - break; - fprintf(stderr, "Error probing interface \"%s\"\n", - (*port)->name); - } - if (*port == NULL) { - fprintf(stderr, "Cannot handle device \"%s\"\n", - ops->device); - return PORT_ERR_UNKNOWN; - } - - *outport = *port; - return PORT_ERR_OK; -} diff --git a/macosx/src/stm32flash_serial/src/port.h b/macosx/src/stm32flash_serial/src/port.h deleted file mode 100644 index 290f03496..000000000 --- a/macosx/src/stm32flash_serial/src/port.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _H_PORT -#define _H_PORT - -typedef enum { - PORT_ERR_OK = 0, - PORT_ERR_NODEV, /* No such device */ - PORT_ERR_TIMEDOUT, /* Operation timed out */ - PORT_ERR_UNKNOWN, -} port_err_t; - -/* flags */ -#define PORT_BYTE (1 << 0) /* byte (not frame) oriented */ -#define PORT_GVR_ETX (1 << 1) /* cmd GVR returns protection status */ -#define PORT_CMD_INIT (1 << 2) /* use INIT cmd to autodetect speed */ -#define PORT_RETRY (1 << 3) /* allowed read() retry after timeout */ -#define PORT_STRETCH_W (1 << 4) /* warning for no-stretching commands */ - -/* all options and flags used to open and configure an interface */ -struct port_options { - const char *device; - serial_baud_t baudRate; - const char *serial_mode; - int bus_addr; - int rx_frame_max; - int tx_frame_max; -}; - -/* - * Specify the length of reply for command GET - * This is helpful for frame-oriented protocols, e.g. i2c, to avoid time - * consuming try-fail-timeout-retry operation. - * On byte-oriented protocols, i.e. UART, this information would be skipped - * after read the first byte, so not needed. - */ -struct varlen_cmd { - uint8_t version; - uint8_t length; -}; - -struct port_interface { - const char *name; - unsigned flags; - port_err_t (*open)(struct port_interface *port, struct port_options *ops); - port_err_t (*close)(struct port_interface *port); - port_err_t (*read)(struct port_interface *port, void *buf, size_t nbyte); - port_err_t (*write)(struct port_interface *port, void *buf, size_t nbyte); - port_err_t (*gpio)(struct port_interface *port, serial_gpio_t n, int level); - const char *(*get_cfg_str)(struct port_interface *port); - struct varlen_cmd *cmd_get_reply; - void *private; -}; - -port_err_t port_open(struct port_options *ops, struct port_interface **outport); - -#endif diff --git a/macosx/src/stm32flash_serial/src/protocol.txt b/macosx/src/stm32flash_serial/src/protocol.txt deleted file mode 100644 index 039109908..000000000 --- a/macosx/src/stm32flash_serial/src/protocol.txt +++ /dev/null @@ -1,19 +0,0 @@ -The communication protocol used by ST bootloader is documented in following ST -application notes, depending on communication port. - -In current version of stm32flash are supported only UART and I2C ports. - -* AN3154: CAN protocol used in the STM32 bootloader - http://www.st.com/web/en/resource/technical/document/application_note/CD00264321.pdf - -* AN3155: USART protocol used in the STM32(TM) bootloader - http://www.st.com/web/en/resource/technical/document/application_note/CD00264342.pdf - -* AN4221: I2C protocol used in the STM32 bootloader - http://www.st.com/web/en/resource/technical/document/application_note/DM00072315.pdf - -* AN4286: SPI protocol used in the STM32 bootloader - http://www.st.com/web/en/resource/technical/document/application_note/DM00081379.pdf - -Boot mode selection for STM32 is documented in ST application note AN2606, available in ST website: - http://www.st.com/web/en/resource/technical/document/application_note/CD00167594.pdf diff --git a/macosx/src/stm32flash_serial/src/serial.h b/macosx/src/stm32flash_serial/src/serial.h deleted file mode 100644 index 227ba163b..000000000 --- a/macosx/src/stm32flash_serial/src/serial.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _SERIAL_H -#define _SERIAL_H - -typedef struct serial serial_t; - -typedef enum { - SERIAL_PARITY_NONE, - SERIAL_PARITY_EVEN, - SERIAL_PARITY_ODD, - - SERIAL_PARITY_INVALID -} serial_parity_t; - -typedef enum { - SERIAL_BITS_5, - SERIAL_BITS_6, - SERIAL_BITS_7, - SERIAL_BITS_8, - - SERIAL_BITS_INVALID -} serial_bits_t; - -typedef enum { - SERIAL_BAUD_1200, - SERIAL_BAUD_1800, - SERIAL_BAUD_2400, - SERIAL_BAUD_4800, - SERIAL_BAUD_9600, - SERIAL_BAUD_19200, - SERIAL_BAUD_38400, - SERIAL_BAUD_57600, - SERIAL_BAUD_115200, - SERIAL_BAUD_128000, - SERIAL_BAUD_230400, - SERIAL_BAUD_256000, - SERIAL_BAUD_460800, - SERIAL_BAUD_500000, - SERIAL_BAUD_576000, - SERIAL_BAUD_921600, - SERIAL_BAUD_1000000, - SERIAL_BAUD_1500000, - SERIAL_BAUD_2000000, - - SERIAL_BAUD_INVALID -} serial_baud_t; - -typedef enum { - SERIAL_STOPBIT_1, - SERIAL_STOPBIT_2, - - SERIAL_STOPBIT_INVALID -} serial_stopbit_t; - -typedef enum { - GPIO_RTS = 1, - GPIO_DTR, - GPIO_BRK, -} serial_gpio_t; - -/* common helper functions */ -serial_baud_t serial_get_baud(const unsigned int baud); -unsigned int serial_get_baud_int(const serial_baud_t baud); -serial_bits_t serial_get_bits(const char *mode); -unsigned int serial_get_bits_int(const serial_bits_t bits); -serial_parity_t serial_get_parity(const char *mode); -char serial_get_parity_str(const serial_parity_t parity); -serial_stopbit_t serial_get_stopbit(const char *mode); -unsigned int serial_get_stopbit_int(const serial_stopbit_t stopbit); - -#endif diff --git a/macosx/src/stm32flash_serial/src/serial_common.c b/macosx/src/stm32flash_serial/src/serial_common.c deleted file mode 100644 index 43e48e1ac..000000000 --- a/macosx/src/stm32flash_serial/src/serial_common.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "serial.h" - -serial_baud_t serial_get_baud(const unsigned int baud) { - switch(baud) { - case 1200: return SERIAL_BAUD_1200 ; - case 1800: return SERIAL_BAUD_1800 ; - case 2400: return SERIAL_BAUD_2400 ; - case 4800: return SERIAL_BAUD_4800 ; - case 9600: return SERIAL_BAUD_9600 ; - case 19200: return SERIAL_BAUD_19200 ; - case 38400: return SERIAL_BAUD_38400 ; - case 57600: return SERIAL_BAUD_57600 ; - case 115200: return SERIAL_BAUD_115200; - case 128000: return SERIAL_BAUD_128000; - case 230400: return SERIAL_BAUD_230400; - case 256000: return SERIAL_BAUD_256000; - case 460800: return SERIAL_BAUD_460800; - case 500000: return SERIAL_BAUD_500000; - case 576000: return SERIAL_BAUD_576000; - case 921600: return SERIAL_BAUD_921600; - case 1000000: return SERIAL_BAUD_1000000; - case 1500000: return SERIAL_BAUD_1500000; - case 2000000: return SERIAL_BAUD_2000000; - - default: - return SERIAL_BAUD_INVALID; - } -} - -unsigned int serial_get_baud_int(const serial_baud_t baud) { - switch(baud) { - case SERIAL_BAUD_1200 : return 1200 ; - case SERIAL_BAUD_1800 : return 1800 ; - case SERIAL_BAUD_2400 : return 2400 ; - case SERIAL_BAUD_4800 : return 4800 ; - case SERIAL_BAUD_9600 : return 9600 ; - case SERIAL_BAUD_19200 : return 19200 ; - case SERIAL_BAUD_38400 : return 38400 ; - case SERIAL_BAUD_57600 : return 57600 ; - case SERIAL_BAUD_115200: return 115200; - case SERIAL_BAUD_128000: return 128000; - case SERIAL_BAUD_230400: return 230400; - case SERIAL_BAUD_256000: return 256000; - case SERIAL_BAUD_460800: return 460800; - case SERIAL_BAUD_500000: return 500000; - case SERIAL_BAUD_576000: return 576000; - case SERIAL_BAUD_921600: return 921600; - case SERIAL_BAUD_1000000: return 1000000; - case SERIAL_BAUD_1500000: return 1500000; - case SERIAL_BAUD_2000000: return 2000000; - - case SERIAL_BAUD_INVALID: - default: - return 0; - } -} - -serial_bits_t serial_get_bits(const char *mode) { - if (!mode) - return SERIAL_BITS_INVALID; - switch(mode[0]) { - case '5': return SERIAL_BITS_5; - case '6': return SERIAL_BITS_6; - case '7': return SERIAL_BITS_7; - case '8': return SERIAL_BITS_8; - - default: - return SERIAL_BITS_INVALID; - } -} - -unsigned int serial_get_bits_int(const serial_bits_t bits) { - switch(bits) { - case SERIAL_BITS_5: return 5; - case SERIAL_BITS_6: return 6; - case SERIAL_BITS_7: return 7; - case SERIAL_BITS_8: return 8; - - default: - return 0; - } -} - -serial_parity_t serial_get_parity(const char *mode) { - if (!mode || !mode[0]) - return SERIAL_PARITY_INVALID; - switch(mode[1]) { - case 'N': - case 'n': - return SERIAL_PARITY_NONE; - case 'E': - case 'e': - return SERIAL_PARITY_EVEN; - case 'O': - case 'o': - return SERIAL_PARITY_ODD; - - default: - return SERIAL_PARITY_INVALID; - } -} - -char serial_get_parity_str(const serial_parity_t parity) { - switch(parity) { - case SERIAL_PARITY_NONE: return 'N'; - case SERIAL_PARITY_EVEN: return 'E'; - case SERIAL_PARITY_ODD : return 'O'; - - default: - return ' '; - } -} - -serial_stopbit_t serial_get_stopbit(const char *mode) { - if (!mode || !mode[0] || !mode[1]) - return SERIAL_STOPBIT_INVALID; - switch(mode[2]) { - case '1': return SERIAL_STOPBIT_1; - case '2': return SERIAL_STOPBIT_2; - - default: - return SERIAL_STOPBIT_INVALID; - } -} - -unsigned int serial_get_stopbit_int(const serial_stopbit_t stopbit) { - switch(stopbit) { - case SERIAL_STOPBIT_1: return 1; - case SERIAL_STOPBIT_2: return 2; - - default: - return 0; - } -} - diff --git a/macosx/src/stm32flash_serial/src/serial_platform.c b/macosx/src/stm32flash_serial/src/serial_platform.c deleted file mode 100644 index 98e256921..000000000 --- a/macosx/src/stm32flash_serial/src/serial_platform.c +++ /dev/null @@ -1,5 +0,0 @@ -#if defined(__WIN32__) || defined(__CYGWIN__) -# include "serial_w32.c" -#else -# include "serial_posix.c" -#endif diff --git a/macosx/src/stm32flash_serial/src/serial_posix.c b/macosx/src/stm32flash_serial/src/serial_posix.c deleted file mode 100644 index 284b35b20..000000000 --- a/macosx/src/stm32flash_serial/src/serial_posix.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "serial.h" -#include "port.h" - -struct serial { - int fd; - struct termios oldtio; - struct termios newtio; - char setup_str[11]; -}; - -static serial_t *serial_open(const char *device) -{ - serial_t *h = calloc(sizeof(serial_t), 1); - - h->fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); - if (h->fd < 0) { - free(h); - return NULL; - } - fcntl(h->fd, F_SETFL, 0); - - tcgetattr(h->fd, &h->oldtio); - tcgetattr(h->fd, &h->newtio); - - return h; -} - -static void serial_flush(const serial_t *h) -{ - tcflush(h->fd, TCIFLUSH); -} - -static void serial_close(serial_t *h) -{ - serial_flush(h); - tcsetattr(h->fd, TCSANOW, &h->oldtio); - close(h->fd); - free(h); -} - -static port_err_t serial_setup(serial_t *h, const serial_baud_t baud, - const serial_bits_t bits, - const serial_parity_t parity, - const serial_stopbit_t stopbit) -{ - speed_t port_baud; - tcflag_t port_bits; - tcflag_t port_parity; - tcflag_t port_stop; - struct termios settings; - - switch (baud) { - case SERIAL_BAUD_1200: port_baud = B1200; break; - case SERIAL_BAUD_1800: port_baud = B1800; break; - case SERIAL_BAUD_2400: port_baud = B2400; break; - case SERIAL_BAUD_4800: port_baud = B4800; break; - case SERIAL_BAUD_9600: port_baud = B9600; break; - case SERIAL_BAUD_19200: port_baud = B19200; break; - case SERIAL_BAUD_38400: port_baud = B38400; break; - case SERIAL_BAUD_57600: port_baud = B57600; break; - case SERIAL_BAUD_115200: port_baud = B115200; break; - case SERIAL_BAUD_230400: port_baud = B230400; break; -#ifdef B460800 - case SERIAL_BAUD_460800: port_baud = B460800; break; -#endif /* B460800 */ -#ifdef B921600 - case SERIAL_BAUD_921600: port_baud = B921600; break; -#endif /* B921600 */ -#ifdef B500000 - case SERIAL_BAUD_500000: port_baud = B500000; break; -#endif /* B500000 */ -#ifdef B576000 - case SERIAL_BAUD_576000: port_baud = B576000; break; -#endif /* B576000 */ -#ifdef B1000000 - case SERIAL_BAUD_1000000: port_baud = B1000000; break; -#endif /* B1000000 */ -#ifdef B1500000 - case SERIAL_BAUD_1500000: port_baud = B1500000; break; -#endif /* B1500000 */ -#ifdef B2000000 - case SERIAL_BAUD_2000000: port_baud = B2000000; break; -#endif /* B2000000 */ - - case SERIAL_BAUD_INVALID: - default: - return PORT_ERR_UNKNOWN; - } - - switch (bits) { - case SERIAL_BITS_5: port_bits = CS5; break; - case SERIAL_BITS_6: port_bits = CS6; break; - case SERIAL_BITS_7: port_bits = CS7; break; - case SERIAL_BITS_8: port_bits = CS8; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (parity) { - case SERIAL_PARITY_NONE: port_parity = 0; break; - case SERIAL_PARITY_EVEN: port_parity = PARENB; break; - case SERIAL_PARITY_ODD: port_parity = PARENB | PARODD; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (stopbit) { - case SERIAL_STOPBIT_1: port_stop = 0; break; - case SERIAL_STOPBIT_2: port_stop = CSTOPB; break; - - default: - return PORT_ERR_UNKNOWN; - } - - /* reset the settings */ -#ifndef __sun /* Used by GNU and BSD. Ignore __SVR4 in test. */ - cfmakeraw(&h->newtio); -#else /* __sun */ - h->newtio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR - | IGNCR | ICRNL | IXON); - if (port_parity) - h->newtio.c_iflag |= INPCK; - - h->newtio.c_oflag &= ~OPOST; - h->newtio.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - h->newtio.c_cflag &= ~(CSIZE | PARENB); - h->newtio.c_cflag |= CS8; -#endif /* __sun */ -#ifdef __QNXNTO__ - h->newtio.c_cflag &= ~(CSIZE | IHFLOW | OHFLOW); -#else - h->newtio.c_cflag &= ~(CSIZE | CRTSCTS); -#endif - h->newtio.c_cflag &= ~(CSIZE | CRTSCTS); - h->newtio.c_iflag &= ~(IXON | IXOFF | IXANY | IGNPAR); - h->newtio.c_lflag &= ~(ECHOK | ECHOCTL | ECHOKE); - h->newtio.c_oflag &= ~(OPOST | ONLCR); - - /* setup the new settings */ - cfsetispeed(&h->newtio, port_baud); - cfsetospeed(&h->newtio, port_baud); - h->newtio.c_cflag |= - port_parity | - port_bits | - port_stop | - CLOCAL | - CREAD; - - h->newtio.c_cc[VMIN] = 0; - h->newtio.c_cc[VTIME] = 5; /* in units of 0.1 s */ - - /* set the settings */ - serial_flush(h); - if (tcsetattr(h->fd, TCSANOW, &h->newtio) != 0) - return PORT_ERR_UNKNOWN; - -/* this check fails on CDC-ACM devices, bits 16 and 17 of cflag differ! - * it has been disabled below for now -jcw, 2015-11-09 - if (settings.c_cflag != h->newtio.c_cflag) - fprintf(stderr, "c_cflag mismatch %lx\n", - settings.c_cflag ^ h->newtio.c_cflag); - */ - - /* confirm they were set */ - tcgetattr(h->fd, &settings); - if (settings.c_iflag != h->newtio.c_iflag || - settings.c_oflag != h->newtio.c_oflag || - //settings.c_cflag != h->newtio.c_cflag || - settings.c_lflag != h->newtio.c_lflag) - return PORT_ERR_UNKNOWN; - - snprintf(h->setup_str, sizeof(h->setup_str), "%u %d%c%d", - serial_get_baud_int(baud), - serial_get_bits_int(bits), - serial_get_parity_str(parity), - serial_get_stopbit_int(stopbit)); - return PORT_ERR_OK; -} - -/* - * Roger clark. - * This function is no longer used. But has just been commented out in case it needs - * to be reinstated in the future - -static int startswith(const char *haystack, const char *needle) { - return strncmp(haystack, needle, strlen(needle)) == 0; -} -*/ - -static int is_tty(const char *path) { - char resolved[PATH_MAX]; - - if(!realpath(path, resolved)) return 0; - - - /* - * Roger Clark - * Commented out this check, because on OSX some devices are /dev/cu - * and some users use symbolic links to devices, hence the name may not even start - * with /dev - - if(startswith(resolved, "/dev/tty")) return 1; - - return 0; - */ - - return 1; -} - -static port_err_t serial_posix_open(struct port_interface *port, - struct port_options *ops) -{ - serial_t *h; - - /* 1. check device name match */ - if (!is_tty(ops->device)) - return PORT_ERR_NODEV; - - /* 2. check options */ - if (ops->baudRate == SERIAL_BAUD_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_bits(ops->serial_mode) == SERIAL_BITS_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_parity(ops->serial_mode) == SERIAL_PARITY_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_stopbit(ops->serial_mode) == SERIAL_STOPBIT_INVALID) - return PORT_ERR_UNKNOWN; - - /* 3. open it */ - h = serial_open(ops->device); - if (h == NULL) - return PORT_ERR_UNKNOWN; - - /* 4. set options */ - if (serial_setup(h, ops->baudRate, - serial_get_bits(ops->serial_mode), - serial_get_parity(ops->serial_mode), - serial_get_stopbit(ops->serial_mode) - ) != PORT_ERR_OK) { - serial_close(h); - return PORT_ERR_UNKNOWN; - } - - port->private = h; - return PORT_ERR_OK; -} - -static port_err_t serial_posix_close(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - serial_close(h); - port->private = NULL; - return PORT_ERR_OK; -} - -static port_err_t serial_posix_read(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - ssize_t r; - uint8_t *pos = (uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - r = read(h->fd, pos, nbyte); - if (r == 0) - return PORT_ERR_TIMEDOUT; - if (r < 0) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_posix_write(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - ssize_t r; - const uint8_t *pos = (const uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - r = write(h->fd, pos, nbyte); - if (r < 1) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_posix_gpio(struct port_interface *port, - serial_gpio_t n, int level) -{ - serial_t *h; - int bit, lines; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - switch (n) { - case GPIO_RTS: - bit = TIOCM_RTS; - break; - - case GPIO_DTR: - bit = TIOCM_DTR; - break; - - case GPIO_BRK: - if (level == 0) - return PORT_ERR_OK; - if (tcsendbreak(h->fd, 1)) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; - - default: - return PORT_ERR_UNKNOWN; - } - - /* handle RTS/DTR */ - if (ioctl(h->fd, TIOCMGET, &lines)) - return PORT_ERR_UNKNOWN; - lines = level ? lines | bit : lines & ~bit; - if (ioctl(h->fd, TIOCMSET, &lines)) - return PORT_ERR_UNKNOWN; - - return PORT_ERR_OK; -} - -static const char *serial_posix_get_cfg_str(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - return h ? h->setup_str : "INVALID"; -} - -struct port_interface port_serial = { - .name = "serial_posix", - .flags = PORT_BYTE | PORT_GVR_ETX | PORT_CMD_INIT | PORT_RETRY, - .open = serial_posix_open, - .close = serial_posix_close, - .read = serial_posix_read, - .write = serial_posix_write, - .gpio = serial_posix_gpio, - .get_cfg_str = serial_posix_get_cfg_str, -}; diff --git a/macosx/src/stm32flash_serial/src/serial_w32.c b/macosx/src/stm32flash_serial/src/serial_w32.c deleted file mode 100644 index 56772c0a0..000000000 --- a/macosx/src/stm32flash_serial/src/serial_w32.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2010 Gareth McMullin - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "serial.h" -#include "port.h" - -struct serial { - HANDLE fd; - DCB oldtio; - DCB newtio; - char setup_str[11]; -}; - -static serial_t *serial_open(const char *device) -{ - serial_t *h = calloc(sizeof(serial_t), 1); - char *devName; - - /* timeout in ms */ - COMMTIMEOUTS timeouts = {MAXDWORD, MAXDWORD, 500, 0, 0}; - - /* Fix the device name if required */ - if (strlen(device) > 4 && device[0] != '\\') { - devName = calloc(1, strlen(device) + 5); - sprintf(devName, "\\\\.\\%s", device); - } else { - devName = (char *)device; - } - - /* Create file handle for port */ - h->fd = CreateFile(devName, GENERIC_READ | GENERIC_WRITE, - 0, /* Exclusive access */ - NULL, /* No security */ - OPEN_EXISTING, - 0, /* No overlap */ - NULL); - - if (devName != device) - free(devName); - - if (h->fd == INVALID_HANDLE_VALUE) { - if (GetLastError() == ERROR_FILE_NOT_FOUND) - fprintf(stderr, "File not found: %s\n", device); - return NULL; - } - - SetupComm(h->fd, 4096, 4096); /* Set input and output buffer size */ - - SetCommTimeouts(h->fd, &timeouts); - - SetCommMask(h->fd, EV_ERR); /* Notify us of error events */ - - GetCommState(h->fd, &h->oldtio); /* Retrieve port parameters */ - GetCommState(h->fd, &h->newtio); /* Retrieve port parameters */ - - /* PurgeComm(h->fd, PURGE_RXABORT | PURGE_TXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); */ - - return h; -} - -static void serial_flush(const serial_t *h) -{ - /* We shouldn't need to flush in non-overlapping (blocking) mode */ - /* tcflush(h->fd, TCIFLUSH); */ -} - -static void serial_close(serial_t *h) -{ - serial_flush(h); - SetCommState(h->fd, &h->oldtio); - CloseHandle(h->fd); - free(h); -} - -static port_err_t serial_setup(serial_t *h, - const serial_baud_t baud, - const serial_bits_t bits, - const serial_parity_t parity, - const serial_stopbit_t stopbit) -{ - switch (baud) { - case SERIAL_BAUD_1200: h->newtio.BaudRate = CBR_1200; break; - /* case SERIAL_BAUD_1800: h->newtio.BaudRate = CBR_1800; break; */ - case SERIAL_BAUD_2400: h->newtio.BaudRate = CBR_2400; break; - case SERIAL_BAUD_4800: h->newtio.BaudRate = CBR_4800; break; - case SERIAL_BAUD_9600: h->newtio.BaudRate = CBR_9600; break; - case SERIAL_BAUD_19200: h->newtio.BaudRate = CBR_19200; break; - case SERIAL_BAUD_38400: h->newtio.BaudRate = CBR_38400; break; - case SERIAL_BAUD_57600: h->newtio.BaudRate = CBR_57600; break; - case SERIAL_BAUD_115200: h->newtio.BaudRate = CBR_115200; break; - case SERIAL_BAUD_128000: h->newtio.BaudRate = CBR_128000; break; - case SERIAL_BAUD_256000: h->newtio.BaudRate = CBR_256000; break; - /* These are not defined in WinBase.h and might work or not */ - case SERIAL_BAUD_230400: h->newtio.BaudRate = 230400; break; - case SERIAL_BAUD_460800: h->newtio.BaudRate = 460800; break; - case SERIAL_BAUD_500000: h->newtio.BaudRate = 500000; break; - case SERIAL_BAUD_576000: h->newtio.BaudRate = 576000; break; - case SERIAL_BAUD_921600: h->newtio.BaudRate = 921600; break; - case SERIAL_BAUD_1000000: h->newtio.BaudRate = 1000000; break; - case SERIAL_BAUD_1500000: h->newtio.BaudRate = 1500000; break; - case SERIAL_BAUD_2000000: h->newtio.BaudRate = 2000000; break; - case SERIAL_BAUD_INVALID: - - default: - return PORT_ERR_UNKNOWN; - } - - switch (bits) { - case SERIAL_BITS_5: h->newtio.ByteSize = 5; break; - case SERIAL_BITS_6: h->newtio.ByteSize = 6; break; - case SERIAL_BITS_7: h->newtio.ByteSize = 7; break; - case SERIAL_BITS_8: h->newtio.ByteSize = 8; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (parity) { - case SERIAL_PARITY_NONE: h->newtio.Parity = NOPARITY; break; - case SERIAL_PARITY_EVEN: h->newtio.Parity = EVENPARITY; break; - case SERIAL_PARITY_ODD: h->newtio.Parity = ODDPARITY; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (stopbit) { - case SERIAL_STOPBIT_1: h->newtio.StopBits = ONESTOPBIT; break; - case SERIAL_STOPBIT_2: h->newtio.StopBits = TWOSTOPBITS; break; - - default: - return PORT_ERR_UNKNOWN; - } - - /* reset the settings */ - h->newtio.fOutxCtsFlow = FALSE; - h->newtio.fOutxDsrFlow = FALSE; - h->newtio.fOutX = FALSE; - h->newtio.fInX = FALSE; - h->newtio.fNull = 0; - h->newtio.fAbortOnError = 0; - - /* set the settings */ - serial_flush(h); - if (!SetCommState(h->fd, &h->newtio)) - return PORT_ERR_UNKNOWN; - - snprintf(h->setup_str, sizeof(h->setup_str), "%u %d%c%d", - serial_get_baud_int(baud), - serial_get_bits_int(bits), - serial_get_parity_str(parity), - serial_get_stopbit_int(stopbit) - ); - return PORT_ERR_OK; -} - -static port_err_t serial_w32_open(struct port_interface *port, - struct port_options *ops) -{ - serial_t *h; - - /* 1. check device name match */ - if (!((strlen(ops->device) == 4 || strlen(ops->device) == 5) - && !strncmp(ops->device, "COM", 3) && isdigit(ops->device[3])) - && !(!strncmp(ops->device, "\\\\.\\COM", strlen("\\\\.\\COM")) - && isdigit(ops->device[strlen("\\\\.\\COM")]))) - return PORT_ERR_NODEV; - - /* 2. check options */ - if (ops->baudRate == SERIAL_BAUD_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_bits(ops->serial_mode) == SERIAL_BITS_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_parity(ops->serial_mode) == SERIAL_PARITY_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_stopbit(ops->serial_mode) == SERIAL_STOPBIT_INVALID) - return PORT_ERR_UNKNOWN; - - /* 3. open it */ - h = serial_open(ops->device); - if (h == NULL) - return PORT_ERR_UNKNOWN; - - /* 4. set options */ - if (serial_setup(h, ops->baudRate, - serial_get_bits(ops->serial_mode), - serial_get_parity(ops->serial_mode), - serial_get_stopbit(ops->serial_mode) - ) != PORT_ERR_OK) { - serial_close(h); - return PORT_ERR_UNKNOWN; - } - - port->private = h; - return PORT_ERR_OK; -} - -static port_err_t serial_w32_close(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - serial_close(h); - port->private = NULL; - return PORT_ERR_OK; -} - -static port_err_t serial_w32_read(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - DWORD r; - uint8_t *pos = (uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - ReadFile(h->fd, pos, nbyte, &r, NULL); - if (r == 0) - return PORT_ERR_TIMEDOUT; - if (r < 0) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_w32_write(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - DWORD r; - uint8_t *pos = (uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - if (!WriteFile(h->fd, pos, nbyte, &r, NULL)) - return PORT_ERR_UNKNOWN; - if (r < 1) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_w32_gpio(struct port_interface *port, - serial_gpio_t n, int level) -{ - serial_t *h; - int bit; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - switch (n) { - case GPIO_RTS: - bit = level ? SETRTS : CLRRTS; - break; - - case GPIO_DTR: - bit = level ? SETDTR : CLRDTR; - break; - - case GPIO_BRK: - if (level == 0) - return PORT_ERR_OK; - if (EscapeCommFunction(h->fd, SETBREAK) == 0) - return PORT_ERR_UNKNOWN; - usleep(500000); - if (EscapeCommFunction(h->fd, CLRBREAK) == 0) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; - - default: - return PORT_ERR_UNKNOWN; - } - - /* handle RTS/DTR */ - if (EscapeCommFunction(h->fd, bit) == 0) - return PORT_ERR_UNKNOWN; - - return PORT_ERR_OK; -} - -static const char *serial_w32_get_cfg_str(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - return h ? h->setup_str : "INVALID"; -} - -struct port_interface port_serial = { - .name = "serial_w32", - .flags = PORT_BYTE | PORT_GVR_ETX | PORT_CMD_INIT | PORT_RETRY, - .open = serial_w32_open, - .close = serial_w32_close, - .read = serial_w32_read, - .write = serial_w32_write, - .gpio = serial_w32_gpio, - .get_cfg_str = serial_w32_get_cfg_str, -}; diff --git a/macosx/src/stm32flash_serial/src/stm32.c b/macosx/src/stm32flash_serial/src/stm32.c deleted file mode 100644 index 74047d244..000000000 --- a/macosx/src/stm32flash_serial/src/stm32.c +++ /dev/null @@ -1,1048 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright 2010 Geoffrey McRae - Copyright 2012-2014 Tormod Volden - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include - -#include "stm32.h" -#include "port.h" -#include "utils.h" - -#define STM32_ACK 0x79 -#define STM32_NACK 0x1F -#define STM32_BUSY 0x76 - -#define STM32_CMD_INIT 0x7F -#define STM32_CMD_GET 0x00 /* get the version and command supported */ -#define STM32_CMD_GVR 0x01 /* get version and read protection status */ -#define STM32_CMD_GID 0x02 /* get ID */ -#define STM32_CMD_RM 0x11 /* read memory */ -#define STM32_CMD_GO 0x21 /* go */ -#define STM32_CMD_WM 0x31 /* write memory */ -#define STM32_CMD_WM_NS 0x32 /* no-stretch write memory */ -#define STM32_CMD_ER 0x43 /* erase */ -#define STM32_CMD_EE 0x44 /* extended erase */ -#define STM32_CMD_EE_NS 0x45 /* extended erase no-stretch */ -#define STM32_CMD_WP 0x63 /* write protect */ -#define STM32_CMD_WP_NS 0x64 /* write protect no-stretch */ -#define STM32_CMD_UW 0x73 /* write unprotect */ -#define STM32_CMD_UW_NS 0x74 /* write unprotect no-stretch */ -#define STM32_CMD_RP 0x82 /* readout protect */ -#define STM32_CMD_RP_NS 0x83 /* readout protect no-stretch */ -#define STM32_CMD_UR 0x92 /* readout unprotect */ -#define STM32_CMD_UR_NS 0x93 /* readout unprotect no-stretch */ -#define STM32_CMD_CRC 0xA1 /* compute CRC */ -#define STM32_CMD_ERR 0xFF /* not a valid command */ - -#define STM32_RESYNC_TIMEOUT 35 /* seconds */ -#define STM32_MASSERASE_TIMEOUT 35 /* seconds */ -#define STM32_SECTERASE_TIMEOUT 5 /* seconds */ -#define STM32_BLKWRITE_TIMEOUT 1 /* seconds */ -#define STM32_WUNPROT_TIMEOUT 1 /* seconds */ -#define STM32_WPROT_TIMEOUT 1 /* seconds */ -#define STM32_RPROT_TIMEOUT 1 /* seconds */ - -#define STM32_CMD_GET_LENGTH 17 /* bytes in the reply */ - -struct stm32_cmd { - uint8_t get; - uint8_t gvr; - uint8_t gid; - uint8_t rm; - uint8_t go; - uint8_t wm; - uint8_t er; /* this may be extended erase */ - uint8_t wp; - uint8_t uw; - uint8_t rp; - uint8_t ur; - uint8_t crc; -}; - -/* Reset code for ARMv7-M (Cortex-M3) and ARMv6-M (Cortex-M0) - * see ARMv7-M or ARMv6-M Architecture Reference Manual (table B3-8) - * or "The definitive guide to the ARM Cortex-M3", section 14.4. - */ -static const uint8_t stm_reset_code[] = { - 0x01, 0x49, // ldr r1, [pc, #4] ; () - 0x02, 0x4A, // ldr r2, [pc, #8] ; () - 0x0A, 0x60, // str r2, [r1, #0] - 0xfe, 0xe7, // endless: b endless - 0x0c, 0xed, 0x00, 0xe0, // .word 0xe000ed0c = NVIC AIRCR register address - 0x04, 0x00, 0xfa, 0x05 // .word 0x05fa0004 = VECTKEY | SYSRESETREQ -}; - -static const uint32_t stm_reset_code_length = sizeof(stm_reset_code); - -extern const stm32_dev_t devices[]; - -static void stm32_warn_stretching(const char *f) -{ - fprintf(stderr, "Attention !!!\n"); - fprintf(stderr, "\tThis %s error could be caused by your I2C\n", f); - fprintf(stderr, "\tcontroller not accepting \"clock stretching\"\n"); - fprintf(stderr, "\tas required by bootloader.\n"); - fprintf(stderr, "\tCheck \"I2C.txt\" in stm32flash source code.\n"); -} - -static stm32_err_t stm32_get_ack_timeout(const stm32_t *stm, time_t timeout) -{ - struct port_interface *port = stm->port; - uint8_t byte; - port_err_t p_err; - time_t t0, t1; - - if (!(port->flags & PORT_RETRY)) - timeout = 0; - - if (timeout) - time(&t0); - - do { - p_err = port->read(port, &byte, 1); - if (p_err == PORT_ERR_TIMEDOUT && timeout) { - time(&t1); - if (t1 < t0 + timeout) - continue; - } - - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to read ACK byte\n"); - return STM32_ERR_UNKNOWN; - } - - if (byte == STM32_ACK) - return STM32_ERR_OK; - if (byte == STM32_NACK) - return STM32_ERR_NACK; - if (byte != STM32_BUSY) { - fprintf(stderr, "Got byte 0x%02x instead of ACK\n", - byte); - return STM32_ERR_UNKNOWN; - } - } while (1); -} - -static stm32_err_t stm32_get_ack(const stm32_t *stm) -{ - return stm32_get_ack_timeout(stm, 0); -} - -static stm32_err_t stm32_send_command_timeout(const stm32_t *stm, - const uint8_t cmd, - time_t timeout) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - port_err_t p_err; - uint8_t buf[2]; - - buf[0] = cmd; - buf[1] = cmd ^ 0xFF; - p_err = port->write(port, buf, 2); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to send command\n"); - return STM32_ERR_UNKNOWN; - } - s_err = stm32_get_ack_timeout(stm, timeout); - if (s_err == STM32_ERR_OK) - return STM32_ERR_OK; - if (s_err == STM32_ERR_NACK) - fprintf(stderr, "Got NACK from device on command 0x%02x\n", cmd); - else - fprintf(stderr, "Unexpected reply from device on command 0x%02x\n", cmd); - return STM32_ERR_UNKNOWN; -} - -static stm32_err_t stm32_send_command(const stm32_t *stm, const uint8_t cmd) -{ - return stm32_send_command_timeout(stm, cmd, 0); -} - -/* if we have lost sync, send a wrong command and expect a NACK */ -static stm32_err_t stm32_resync(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - port_err_t p_err; - uint8_t buf[2], ack; - time_t t0, t1; - - time(&t0); - t1 = t0; - - buf[0] = STM32_CMD_ERR; - buf[1] = STM32_CMD_ERR ^ 0xFF; - while (t1 < t0 + STM32_RESYNC_TIMEOUT) { - p_err = port->write(port, buf, 2); - if (p_err != PORT_ERR_OK) { - usleep(500000); - time(&t1); - continue; - } - p_err = port->read(port, &ack, 1); - if (p_err != PORT_ERR_OK) { - time(&t1); - continue; - } - if (ack == STM32_NACK) - return STM32_ERR_OK; - time(&t1); - } - return STM32_ERR_UNKNOWN; -} - -/* - * some command receive reply frame with variable length, and length is - * embedded in reply frame itself. - * We can guess the length, but if we guess wrong the protocol gets out - * of sync. - * Use resync for frame oriented interfaces (e.g. I2C) and byte-by-byte - * read for byte oriented interfaces (e.g. UART). - * - * to run safely, data buffer should be allocated for 256+1 bytes - * - * len is value of the first byte in the frame. - */ -static stm32_err_t stm32_guess_len_cmd(const stm32_t *stm, uint8_t cmd, - uint8_t *data, unsigned int len) -{ - struct port_interface *port = stm->port; - port_err_t p_err; - - if (stm32_send_command(stm, cmd) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - if (port->flags & PORT_BYTE) { - /* interface is UART-like */ - p_err = port->read(port, data, 1); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - len = data[0]; - p_err = port->read(port, data + 1, len + 1); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - return STM32_ERR_OK; - } - - p_err = port->read(port, data, len + 2); - if (p_err == PORT_ERR_OK && len == data[0]) - return STM32_ERR_OK; - if (p_err != PORT_ERR_OK) { - /* restart with only one byte */ - if (stm32_resync(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - if (stm32_send_command(stm, cmd) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - p_err = port->read(port, data, 1); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - } - - fprintf(stderr, "Re sync (len = %d)\n", data[0]); - if (stm32_resync(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - len = data[0]; - if (stm32_send_command(stm, cmd) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - p_err = port->read(port, data, len + 2); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - return STM32_ERR_OK; -} - -/* - * Some interface, e.g. UART, requires a specific init sequence to let STM32 - * autodetect the interface speed. - * The sequence is only required one time after reset. - * stm32flash has command line flag "-c" to prevent sending the init sequence - * in case it was already sent before. - * User can easily forget adding "-c". In this case the bootloader would - * interpret the init sequence as part of a command message, then waiting for - * the rest of the message blocking the interface. - * This function sends the init sequence and, in case of timeout, recovers - * the interface. - */ -static stm32_err_t stm32_send_init_seq(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - port_err_t p_err; - uint8_t byte, cmd = STM32_CMD_INIT; - - p_err = port->write(port, &cmd, 1); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to send init to device\n"); - return STM32_ERR_UNKNOWN; - } - p_err = port->read(port, &byte, 1); - if (p_err == PORT_ERR_OK && byte == STM32_ACK) - return STM32_ERR_OK; - if (p_err == PORT_ERR_OK && byte == STM32_NACK) { - /* We could get error later, but let's continue, for now. */ - fprintf(stderr, - "Warning: the interface was not closed properly.\n"); - return STM32_ERR_OK; - } - if (p_err != PORT_ERR_TIMEDOUT) { - fprintf(stderr, "Failed to init device.\n"); - return STM32_ERR_UNKNOWN; - } - - /* - * Check if previous STM32_CMD_INIT was taken as first byte - * of a command. Send a new byte, we should get back a NACK. - */ - p_err = port->write(port, &cmd, 1); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to send init to device\n"); - return STM32_ERR_UNKNOWN; - } - p_err = port->read(port, &byte, 1); - if (p_err == PORT_ERR_OK && byte == STM32_NACK) - return STM32_ERR_OK; - fprintf(stderr, "Failed to init device.\n"); - return STM32_ERR_UNKNOWN; -} - -/* find newer command by higher code */ -#define newer(prev, a) (((prev) == STM32_CMD_ERR) \ - ? (a) \ - : (((prev) > (a)) ? (prev) : (a))) - -stm32_t *stm32_init(struct port_interface *port, const char init) -{ - uint8_t len, val, buf[257]; - stm32_t *stm; - int i, new_cmds; - - stm = calloc(sizeof(stm32_t), 1); - stm->cmd = malloc(sizeof(stm32_cmd_t)); - memset(stm->cmd, STM32_CMD_ERR, sizeof(stm32_cmd_t)); - stm->port = port; - - if ((port->flags & PORT_CMD_INIT) && init) - if (stm32_send_init_seq(stm) != STM32_ERR_OK) - return NULL; - - /* get the version and read protection status */ - if (stm32_send_command(stm, STM32_CMD_GVR) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - /* From AN, only UART bootloader returns 3 bytes */ - len = (port->flags & PORT_GVR_ETX) ? 3 : 1; - if (port->read(port, buf, len) != PORT_ERR_OK) - return NULL; - stm->version = buf[0]; - stm->option1 = (port->flags & PORT_GVR_ETX) ? buf[1] : 0; - stm->option2 = (port->flags & PORT_GVR_ETX) ? buf[2] : 0; - if (stm32_get_ack(stm) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - /* get the bootloader information */ - len = STM32_CMD_GET_LENGTH; - if (port->cmd_get_reply) - for (i = 0; port->cmd_get_reply[i].length; i++) - if (stm->version == port->cmd_get_reply[i].version) { - len = port->cmd_get_reply[i].length; - break; - } - if (stm32_guess_len_cmd(stm, STM32_CMD_GET, buf, len) != STM32_ERR_OK) - return NULL; - len = buf[0] + 1; - stm->bl_version = buf[1]; - new_cmds = 0; - for (i = 1; i < len; i++) { - val = buf[i + 1]; - switch (val) { - case STM32_CMD_GET: - stm->cmd->get = val; break; - case STM32_CMD_GVR: - stm->cmd->gvr = val; break; - case STM32_CMD_GID: - stm->cmd->gid = val; break; - case STM32_CMD_RM: - stm->cmd->rm = val; break; - case STM32_CMD_GO: - stm->cmd->go = val; break; - case STM32_CMD_WM: - case STM32_CMD_WM_NS: - stm->cmd->wm = newer(stm->cmd->wm, val); - break; - case STM32_CMD_ER: - case STM32_CMD_EE: - case STM32_CMD_EE_NS: - stm->cmd->er = newer(stm->cmd->er, val); - break; - case STM32_CMD_WP: - case STM32_CMD_WP_NS: - stm->cmd->wp = newer(stm->cmd->wp, val); - break; - case STM32_CMD_UW: - case STM32_CMD_UW_NS: - stm->cmd->uw = newer(stm->cmd->uw, val); - break; - case STM32_CMD_RP: - case STM32_CMD_RP_NS: - stm->cmd->rp = newer(stm->cmd->rp, val); - break; - case STM32_CMD_UR: - case STM32_CMD_UR_NS: - stm->cmd->ur = newer(stm->cmd->ur, val); - break; - case STM32_CMD_CRC: - stm->cmd->crc = newer(stm->cmd->crc, val); - break; - default: - if (new_cmds++ == 0) - fprintf(stderr, - "GET returns unknown commands (0x%2x", - val); - else - fprintf(stderr, ", 0x%2x", val); - } - } - if (new_cmds) - fprintf(stderr, ")\n"); - if (stm32_get_ack(stm) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - if (stm->cmd->get == STM32_CMD_ERR - || stm->cmd->gvr == STM32_CMD_ERR - || stm->cmd->gid == STM32_CMD_ERR) { - fprintf(stderr, "Error: bootloader did not returned correct information from GET command\n"); - return NULL; - } - - /* get the device ID */ - if (stm32_guess_len_cmd(stm, stm->cmd->gid, buf, 1) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - len = buf[0] + 1; - if (len < 2) { - stm32_close(stm); - fprintf(stderr, "Only %d bytes sent in the PID, unknown/unsupported device\n", len); - return NULL; - } - stm->pid = (buf[1] << 8) | buf[2]; - if (len > 2) { - fprintf(stderr, "This bootloader returns %d extra bytes in PID:", len); - for (i = 2; i <= len ; i++) - fprintf(stderr, " %02x", buf[i]); - fprintf(stderr, "\n"); - } - if (stm32_get_ack(stm) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - stm->dev = devices; - while (stm->dev->id != 0x00 && stm->dev->id != stm->pid) - ++stm->dev; - - if (!stm->dev->id) { - fprintf(stderr, "Unknown/unsupported device (Device ID: 0x%03x)\n", stm->pid); - stm32_close(stm); - return NULL; - } - - return stm; -} - -void stm32_close(stm32_t *stm) -{ - if (stm) - free(stm->cmd); - free(stm); -} - -stm32_err_t stm32_read_memory(const stm32_t *stm, uint32_t address, - uint8_t data[], unsigned int len) -{ - struct port_interface *port = stm->port; - uint8_t buf[5]; - - if (!len) - return STM32_ERR_OK; - - if (len > 256) { - fprintf(stderr, "Error: READ length limit at 256 bytes\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->rm == STM32_CMD_ERR) { - fprintf(stderr, "Error: READ command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->rm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_send_command(stm, len - 1) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (port->read(port, data, len) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - return STM32_ERR_OK; -} - -stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address, - const uint8_t data[], unsigned int len) -{ - struct port_interface *port = stm->port; - uint8_t cs, buf[256 + 2]; - unsigned int i, aligned_len; - stm32_err_t s_err; - - if (!len) - return STM32_ERR_OK; - - if (len > 256) { - fprintf(stderr, "Error: READ length limit at 256 bytes\n"); - return STM32_ERR_UNKNOWN; - } - - /* must be 32bit aligned */ - if (address & 0x3 || len & 0x3) { - fprintf(stderr, "Error: WRITE address and length must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->wm == STM32_CMD_ERR) { - fprintf(stderr, "Error: WRITE command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - /* send the address and checksum */ - if (stm32_send_command(stm, stm->cmd->wm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - aligned_len = (len + 3) & ~3; - cs = aligned_len - 1; - buf[0] = aligned_len - 1; - for (i = 0; i < len; i++) { - cs ^= data[i]; - buf[i + 1] = data[i]; - } - /* padding data */ - for (i = len; i < aligned_len; i++) { - cs ^= 0xFF; - buf[i + 1] = 0xFF; - } - buf[aligned_len + 1] = cs; - if (port->write(port, buf, aligned_len + 2) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_BLKWRITE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->wm != STM32_CMD_WM_NS) - stm32_warn_stretching("write"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_wunprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->uw == STM32_CMD_ERR) { - fprintf(stderr, "Error: WRITE UNPROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->uw) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_WUNPROT_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to WRITE UNPROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->uw != STM32_CMD_UW_NS) - stm32_warn_stretching("WRITE UNPROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_wprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->wp == STM32_CMD_ERR) { - fprintf(stderr, "Error: WRITE PROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->wp) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_WPROT_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to WRITE PROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->wp != STM32_CMD_WP_NS) - stm32_warn_stretching("WRITE PROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_runprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->ur == STM32_CMD_ERR) { - fprintf(stderr, "Error: READOUT UNPROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->ur) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to READOUT UNPROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->ur != STM32_CMD_UR_NS) - stm32_warn_stretching("READOUT UNPROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_readprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->rp == STM32_CMD_ERR) { - fprintf(stderr, "Error: READOUT PROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->rp) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_RPROT_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to READOUT PROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->rp != STM32_CMD_RP_NS) - stm32_warn_stretching("READOUT PROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, uint8_t pages) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - port_err_t p_err; - - if (!pages) - return STM32_ERR_OK; - - if (stm->cmd->er == STM32_CMD_ERR) { - fprintf(stderr, "Error: ERASE command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->er) != STM32_ERR_OK) { - fprintf(stderr, "Can't initiate chip erase!\n"); - return STM32_ERR_UNKNOWN; - } - - /* The erase command reported by the bootloader is either 0x43, 0x44 or 0x45 */ - /* 0x44 is Extended Erase, a 2 byte based protocol and needs to be handled differently. */ - /* 0x45 is clock no-stretching version of Extended Erase for I2C port. */ - if (stm->cmd->er != STM32_CMD_ER) { - /* Not all chips using Extended Erase support mass erase */ - /* Currently known as not supporting mass erase is the Ultra Low Power STM32L15xx range */ - /* So if someone has not overridden the default, but uses one of these chips, take it out of */ - /* mass erase mode, so it will be done page by page. This maximum might not be correct either! */ - if (stm->pid == 0x416 && pages == 0xFF) - pages = 0xF8; /* works for the STM32L152RB with 128Kb flash */ - - if (pages == 0xFF) { - uint8_t buf[3]; - - /* 0xFFFF the magic number for mass erase */ - buf[0] = 0xFF; - buf[1] = 0xFF; - buf[2] = 0x00; /* checksum */ - if (port->write(port, buf, 3) != PORT_ERR_OK) { - fprintf(stderr, "Mass erase error.\n"); - return STM32_ERR_UNKNOWN; - } - s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Mass erase failed. Try specifying the number of pages to be erased.\n"); - if (port->flags & PORT_STRETCH_W - && stm->cmd->er != STM32_CMD_EE_NS) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; - } - - uint16_t pg_num; - uint8_t pg_byte; - uint8_t cs = 0; - uint8_t *buf; - int i = 0; - - buf = malloc(2 + 2 * pages + 1); - if (!buf) - return STM32_ERR_UNKNOWN; - - /* Number of pages to be erased - 1, two bytes, MSB first */ - pg_byte = (pages - 1) >> 8; - buf[i++] = pg_byte; - cs ^= pg_byte; - pg_byte = (pages - 1) & 0xFF; - buf[i++] = pg_byte; - cs ^= pg_byte; - - for (pg_num = spage; pg_num < spage + pages; pg_num++) { - pg_byte = pg_num >> 8; - cs ^= pg_byte; - buf[i++] = pg_byte; - pg_byte = pg_num & 0xFF; - cs ^= pg_byte; - buf[i++] = pg_byte; - } - buf[i++] = cs; - p_err = port->write(port, buf, i); - free(buf); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Page-by-page erase error.\n"); - return STM32_ERR_UNKNOWN; - } - - s_err = stm32_get_ack_timeout(stm, pages * STM32_SECTERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Page-by-page erase failed. Check the maximum pages your device supports.\n"); - if (port->flags & PORT_STRETCH_W - && stm->cmd->er != STM32_CMD_EE_NS) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - - return STM32_ERR_OK; - } - - /* And now the regular erase (0x43) for all other chips */ - if (pages == 0xFF) { - s_err = stm32_send_command_timeout(stm, 0xFF, STM32_MASSERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; - } else { - uint8_t cs = 0; - uint8_t pg_num; - uint8_t *buf; - int i = 0; - - buf = malloc(1 + pages + 1); - if (!buf) - return STM32_ERR_UNKNOWN; - - buf[i++] = pages - 1; - cs ^= (pages-1); - for (pg_num = spage; pg_num < (pages + spage); pg_num++) { - buf[i++] = pg_num; - cs ^= pg_num; - } - buf[i++] = cs; - p_err = port->write(port, buf, i); - free(buf); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Erase failed.\n"); - return STM32_ERR_UNKNOWN; - } - s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; - } -} - -static stm32_err_t stm32_run_raw_code(const stm32_t *stm, - uint32_t target_address, - const uint8_t *code, uint32_t code_size) -{ - uint32_t stack_le = le_u32(0x20002000); - uint32_t code_address_le = le_u32(target_address + 8); - uint32_t length = code_size + 8; - uint8_t *mem, *pos; - uint32_t address, w; - - /* Must be 32-bit aligned */ - if (target_address & 0x3) { - fprintf(stderr, "Error: code address must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - mem = malloc(length); - if (!mem) - return STM32_ERR_UNKNOWN; - - memcpy(mem, &stack_le, sizeof(uint32_t)); - memcpy(mem + 4, &code_address_le, sizeof(uint32_t)); - memcpy(mem + 8, code, code_size); - - pos = mem; - address = target_address; - while (length > 0) { - w = length > 256 ? 256 : length; - if (stm32_write_memory(stm, address, pos, w) != STM32_ERR_OK) { - free(mem); - return STM32_ERR_UNKNOWN; - } - - address += w; - pos += w; - length -= w; - } - - free(mem); - return stm32_go(stm, target_address); -} - -stm32_err_t stm32_go(const stm32_t *stm, uint32_t address) -{ - struct port_interface *port = stm->port; - uint8_t buf[5]; - - if (stm->cmd->go == STM32_CMD_ERR) { - fprintf(stderr, "Error: GO command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->go) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - return STM32_ERR_OK; -} - -stm32_err_t stm32_reset_device(const stm32_t *stm) -{ - uint32_t target_address = stm->dev->ram_start; - - return stm32_run_raw_code(stm, target_address, stm_reset_code, stm_reset_code_length); -} - -stm32_err_t stm32_crc_memory(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc) -{ - struct port_interface *port = stm->port; - uint8_t buf[5]; - - if (address & 0x3 || length & 0x3) { - fprintf(stderr, "Start and end addresses must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->crc == STM32_CMD_ERR) { - fprintf(stderr, "Error: CRC command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->crc) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = length >> 24; - buf[1] = (length >> 16) & 0xFF; - buf[2] = (length >> 8) & 0xFF; - buf[3] = length & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (port->read(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (buf[4] != (buf[0] ^ buf[1] ^ buf[2] ^ buf[3])) - return STM32_ERR_UNKNOWN; - - *crc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; - return STM32_ERR_OK; -} - -/* - * CRC computed by STM32 is similar to the standard crc32_be() - * implemented, for example, in Linux kernel in ./lib/crc32.c - * But STM32 computes it on units of 32 bits word and swaps the - * bytes of the word before the computation. - * Due to byte swap, I cannot use any CRC available in existing - * libraries, so here is a simple not optimized implementation. - */ -#define CRCPOLY_BE 0x04c11db7 -#define CRC_MSBMASK 0x80000000 -#define CRC_INIT_VALUE 0xFFFFFFFF -uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len) -{ - int i; - uint32_t data; - - if (len & 0x3) { - fprintf(stderr, "Buffer length must be multiple of 4 bytes\n"); - return 0; - } - - while (len) { - data = *buf++; - data |= *buf++ << 8; - data |= *buf++ << 16; - data |= *buf++ << 24; - len -= 4; - - crc ^= data; - - for (i = 0; i < 32; i++) - if (crc & CRC_MSBMASK) - crc = (crc << 1) ^ CRCPOLY_BE; - else - crc = (crc << 1); - } - return crc; -} - -stm32_err_t stm32_crc_wrapper(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc) -{ - uint8_t buf[256]; - uint32_t start, total_len, len, current_crc; - - if (address & 0x3 || length & 0x3) { - fprintf(stderr, "Start and end addresses must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->crc != STM32_CMD_ERR) - return stm32_crc_memory(stm, address, length, crc); - - start = address; - total_len = length; - current_crc = CRC_INIT_VALUE; - while (length) { - len = length > 256 ? 256 : length; - if (stm32_read_memory(stm, address, buf, len) != STM32_ERR_OK) { - fprintf(stderr, - "Failed to read memory at address 0x%08x, target write-protected?\n", - address); - return STM32_ERR_UNKNOWN; - } - current_crc = stm32_sw_crc(current_crc, buf, len); - length -= len; - address += len; - - fprintf(stderr, - "\rCRC address 0x%08x (%.2f%%) ", - address, - (100.0f / (float)total_len) * (float)(address - start) - ); - fflush(stderr); - } - fprintf(stderr, "Done.\n"); - *crc = current_crc; - return STM32_ERR_OK; -} diff --git a/macosx/src/stm32flash_serial/src/stm32.h b/macosx/src/stm32flash_serial/src/stm32.h deleted file mode 100644 index 1688fcb4b..000000000 --- a/macosx/src/stm32flash_serial/src/stm32.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _STM32_H -#define _STM32_H - -#include -#include "serial.h" - -#define STM32_MAX_RX_FRAME 256 /* cmd read memory */ -#define STM32_MAX_TX_FRAME (1 + 256 + 1) /* cmd write memory */ - -typedef enum { - STM32_ERR_OK = 0, - STM32_ERR_UNKNOWN, /* Generic error */ - STM32_ERR_NACK, - STM32_ERR_NO_CMD, /* Command not available in bootloader */ -} stm32_err_t; - -typedef struct stm32 stm32_t; -typedef struct stm32_cmd stm32_cmd_t; -typedef struct stm32_dev stm32_dev_t; - -struct stm32 { - const serial_t *serial; - struct port_interface *port; - uint8_t bl_version; - uint8_t version; - uint8_t option1, option2; - uint16_t pid; - stm32_cmd_t *cmd; - const stm32_dev_t *dev; -}; - -struct stm32_dev { - uint16_t id; - const char *name; - uint32_t ram_start, ram_end; - uint32_t fl_start, fl_end; - uint16_t fl_pps; // pages per sector - uint16_t fl_ps; // page size - uint32_t opt_start, opt_end; - uint32_t mem_start, mem_end; -}; - -stm32_t *stm32_init(struct port_interface *port, const char init); -void stm32_close(stm32_t *stm); -stm32_err_t stm32_read_memory(const stm32_t *stm, uint32_t address, - uint8_t data[], unsigned int len); -stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address, - const uint8_t data[], unsigned int len); -stm32_err_t stm32_wunprot_memory(const stm32_t *stm); -stm32_err_t stm32_wprot_memory(const stm32_t *stm); -stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, - uint8_t pages); -stm32_err_t stm32_go(const stm32_t *stm, uint32_t address); -stm32_err_t stm32_reset_device(const stm32_t *stm); -stm32_err_t stm32_readprot_memory(const stm32_t *stm); -stm32_err_t stm32_runprot_memory(const stm32_t *stm); -stm32_err_t stm32_crc_memory(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc); -stm32_err_t stm32_crc_wrapper(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc); -uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len); - -#endif - diff --git a/macosx/src/stm32flash_serial/src/stm32flash.1 b/macosx/src/stm32flash_serial/src/stm32flash.1 deleted file mode 100644 index d37292f6a..000000000 --- a/macosx/src/stm32flash_serial/src/stm32flash.1 +++ /dev/null @@ -1,407 +0,0 @@ -.TH STM32FLASH 1 "2013\-11\-03" STM32FLASH "User command" -.SH NAME -stm32flash \- flashing utility for STM32 and STM32W through UART or I2C -.SH SYNOPSIS -.B stm32flash -.RB [ \-cfhjkouvCR ] -.RB [ \-a -.IR bus_address ] -.RB [ \-b -.IR baud_rate ] -.RB [ \-m -.IR serial_mode ] -.RB [ \-r -.IR filename ] -.RB [ \-w -.IR filename ] -.RB [ \-e -.IR num ] -.RB [ \-n -.IR count ] -.RB [ \-g -.IR address ] -.RB [ \-s -.IR start_page ] -.RB [ \-S -.IR address [: length ]] -.RB [ \-F -.IR RX_length [: TX_length ]] -.RB [ \-i -.IR GPIO_string ] -.RI [ tty_device -.R | -.IR i2c_device ] - -.SH DESCRIPTION -.B stm32flash -reads or writes the flash memory of STM32 and STM32W. - -It requires the STM32[W] to embed a bootloader compliant with ST -application note AN3155. -.B stm32flash -uses the serial port -.I tty_device -to interact with the bootloader of STM32[W]. - -.SH OPTIONS -.TP -.BI "\-a" " bus_address" -Specify address on bus for -.IR i2c_device . -This option is mandatory for I2C interface. - -.TP -.BI "\-b" " baud_rate" -Specify baud rate speed of -.IR tty_device . -Please notice that the ST bootloader can automatically detect the baud rate, -as explaned in chapter 2 of AN3155. -This option could be required together with option -.B "\-c" -or if following interaction with bootloader is expected. -Default is -.IR 57600 . - -.TP -.BI "\-m" " mode" -Specify the format of UART data. -.I mode -is a three characters long string where each character specifies, in -this strict order, character size, parity and stop bits. -The only values currenly used are -.I 8e1 -for standard STM32 bootloader and -.I 8n1 -for standard STM32W bootloader. -Default is -.IR 8e1 . - -.TP -.BI "\-r" " filename" -Specify to read the STM32[W] flash and write its content in -.I filename -in raw binary format (see below -.BR "FORMAT CONVERSION" ). - -.TP -.BI "\-w" " filename" -Specify to write the STM32[W] flash with the content of -.IR filename . -File format can be either raw binary or intel hex (see below -.BR "FORMAT CONVERSION" ). -The file format is automatically detected. -To by\-pass format detection and force binary mode (e.g. to -write an intel hex content in STM32[W] flash), use -.B \-f -option. - -.TP -.B \-u -Specify to disable write\-protection from STM32[W] flash. -The STM32[W] will be reset after this operation. - -.TP -.B \-j -Enable the flash read\-protection. - -.TP -.B \-k -Disable the flash read\-protection. - -.TP -.B \-o -Erase only. - -.TP -.BI "\-e" " num" -Specify to erase only -.I num -pages before writing the flash. Default is to erase the whole flash. With -.B \-e 0 -the flash would not be erased. - -.TP -.B \-v -Specify to verify flash content after write operation. - -.TP -.BI "\-n" " count" -Specify to retry failed writes up to -.I count -times. Default is 10 times. - -.TP -.BI "\-g" " address" -Specify address to start execution from (0 = flash start). - -.TP -.BI "\-s" " start_page" -Specify flash page offset (0 = flash start). - -.TP -.BI "\-S" " address" "[:" "length" "]" -Specify start address and optionally length for read/write/erase/crc operations. - -.TP -.BI "\-F" " RX_length" "[:" "TX_length" "]" -Specify the maximum frame size for the current interface. -Due to STM32 bootloader protocol, host will never handle frames bigger than -256 byte in RX or 258 byte in TX. -Due to current code, lowest limit in RX is 20 byte (to read a complete reply -of command GET). Minimum limit in TX is 5 byte, required by protocol. - -.TP -.B \-f -Force binary parser while reading file with -.BR "\-w" "." - -.TP -.B \-h -Show help. - -.TP -.B \-c -Specify to resume the existing UART connection and don't send initial -INIT sequence to detect baud rate. Baud rate must be kept the same as the -existing connection. This is useful if the reset fails. - -.TP -.BI "\-i" " GPIO_string" -Specify the GPIO sequences on the host to force STM32[W] to enter and -exit bootloader mode. GPIO can either be real GPIO connected from host to -STM32[W] beside the UART connection, or UART's modem signals used as -GPIO. (See below -.B BOOTLOADER GPIO SEQUENCE -for the format of -.I GPIO_string -and further explanation). - -.TP -.B \-C -Specify to compute CRC on memory content. -By default the CRC is computed on the whole flash content. -Use -.B "\-S" -to provide different memory address range. - -.TP -.B \-R -Specify to reset the device at exit. -This option is ignored if either -.BR "\-g" "," -.BR "\-j" "," -.B "\-k" -or -.B "\-u" -is also specified. - -.SH BOOTLOADER GPIO SEQUENCE -This feature is currently available on Linux host only. - -As explained in ST application note AN2606, after reset the STM32 will -execute either the application program in user flash or the bootloader, -depending on the level applied at specific pins of STM32 during reset. - -STM32 bootloader is automatically activated by configuring the pins -BOOT0="high" and BOOT1="low" and then by applying a reset. -Application program in user flash is activated by configuring the pin -BOOT0="low" (the level on BOOT1 is ignored) and then by applying a reset. - -When GPIO from host computer are connected to either configuration and -reset pins of STM32, -.B stm32flash -can control the host GPIO to reset STM32 and to force execution of -bootloader or execution of application program. - -The sequence of GPIO values to entry to and exit from bootloader mode is -provided with command line option -.B "\-i" -.IR "GPIO_string" . - -.PD 0 -The format of -.IR "GPIO_string" " is:" -.RS -GPIO_string = [entry sequence][:[exit sequence]] -.P -sequence = [\-]n[,sequence] -.RE -.P -In the above sequences, negative numbers correspond to GPIO at "low" level; -numbers without sign correspond to GPIO at "high" level. -The value "n" can either be the GPIO number on the host system or the -string "rts", "dtr" or "brk". The strings "rts" and "dtr" drive the -corresponding UART's modem lines RTS and DTR as GPIO. -The string "brk" forces the UART to send a BREAK sequence on TX line; -after BREAK the UART is returned in normal "non\-break" mode. -Note: the string "\-brk" has no effect and is ignored. -.PD - -.PD 0 -As example, let's suppose the following connection between host and STM32: -.IP \(bu 2 -host GPIO_3 connected to reset pin of STM32; -.IP \(bu 2 -host GPIO_4 connected to STM32 pin BOOT0; -.IP \(bu 2 -host GPIO_5 connected to STM32 pin BOOT1. -.PD -.P - -In this case, the sequence to enter in bootloader mode is: first put -GPIO_4="high" and GPIO_5="low"; then send reset pulse by GPIO_3="low" -followed by GPIO_3="high". -The corresponding string for -.I GPIO_string -is "4,\-5,\-3,3". - -To exit from bootloade and run the application program, the sequence is: -put GPIO_4="low"; then send reset pulse. -The corresponding string for -.I GPIO_string -is "\-4,\-3,3". - -The complete command line flag is "\-i 4,\-5,\-3,3:\-4,\-3,3". - -STM32W uses pad PA5 to select boot mode; if during reset PA5 is "low" then -STM32W will enter in bootloader mode; if PA5 is "high" it will execute the -program in flash. - -As example, supposing GPIO_3 connected to PA5 and GPIO_2 to STM32W's reset. -The command: -.PD 0 -.RS -stm32flash \-i \-3,\-2,2:3,\-2,2 /dev/ttyS0 -.RE -provides: -.IP \(bu 2 -entry sequence: GPIO_3=low, GPIO_2=low, GPIO_2=high -.IP \(bu 2 -exit sequence: GPIO_3=high, GPIO_2=low, GPIO_2=high -.PD - -.SH EXAMPLES -Get device information: -.RS -.PD 0 -.P -stm32flash /dev/ttyS0 -.PD -.RE - -Write with verify and then start execution: -.RS -.PD 0 -.P -stm32flash \-w filename \-v \-g 0x0 /dev/ttyS0 -.PD -.RE - -Read flash to file: -.RS -.PD 0 -.P -stm32flash \-r filename /dev/ttyS0 -.PD -.RE - -Start execution: -.RS -.PD 0 -.P -stm32flash \-g 0x0 /dev/ttyS0 -.PD -.RE - -Specify: -.PD 0 -.IP \(bu 2 -entry sequence: RTS=low, DTR=low, DTR=high -.IP \(bu 2 -exit sequence: RTS=high, DTR=low, DTR=high -.P -.RS -stm32flash \-i \-rts,\-dtr,dtr:rts,\-dtr,dtr /dev/ttyS0 -.PD -.RE - -.SH FORMAT CONVERSION -Flash images provided by ST or created with ST tools are often in file -format Motorola S\-Record. -Conversion between raw binary, intel hex and Motorola S\-Record can be -done through software package SRecord. - -.SH AUTHORS -The original software package -.B stm32flash -is written by -.I Geoffrey McRae -and is since 2012 maintained by -.IR "Tormod Volden " . - -Man page and extension to STM32W and I2C are written by -.IR "Antonio Borneo " . - -Please report any bugs at the project homepage -http://stm32flash.googlecode.com . - -.SH SEE ALSO -.BR "srec_cat" "(1)," " srec_intel" "(5)," " srec_motorola" "(5)." - -The communication protocol used by ST bootloader is documented in -following ST application notes, depending on communication port. -The current version of -.B stm32flash -only supports -.I UART -and -.I I2C -ports. -.PD 0 -.P -.IP \(bu 2 -AN3154: CAN protocol used in the STM32 bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/CD00264321.pdf -.RE - -.P -.IP \(bu 2 -AN3155: USART protocol used in the STM32(TM) bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/CD00264342.pdf -.RE - -.P -.IP \(bu 2 -AN4221: I2C protocol used in the STM32 bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/DM00072315.pdf -.RE - -.P -.IP \(bu 2 -AN4286: SPI protocol used in the STM32 bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/DM00081379.pdf -.RE - -.PD - - -Boot mode selection for STM32 is documented in ST application note -AN2606, available from the ST website: -.PD 0 -.P -http://www.st.com/web/en/resource/technical/document/application_note/CD00167594.pdf -.PD - -.SH LICENSE -.B stm32flash -is distributed under GNU GENERAL PUBLIC LICENSE Version 2. -Copy of the license is available within the source code in the file -.IR "gpl\-2.0.txt" . diff --git a/macosx/src/stm32flash_serial/src/utils.c b/macosx/src/stm32flash_serial/src/utils.c deleted file mode 100644 index 271bb3ed7..000000000 --- a/macosx/src/stm32flash_serial/src/utils.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include "utils.h" - -/* detect CPU endian */ -char cpu_le() { - const uint32_t cpu_le_test = 0x12345678; - return ((const unsigned char*)&cpu_le_test)[0] == 0x78; -} - -uint32_t be_u32(const uint32_t v) { - if (cpu_le()) - return ((v & 0xFF000000) >> 24) | - ((v & 0x00FF0000) >> 8) | - ((v & 0x0000FF00) << 8) | - ((v & 0x000000FF) << 24); - return v; -} - -uint32_t le_u32(const uint32_t v) { - if (!cpu_le()) - return ((v & 0xFF000000) >> 24) | - ((v & 0x00FF0000) >> 8) | - ((v & 0x0000FF00) << 8) | - ((v & 0x000000FF) << 24); - return v; -} diff --git a/macosx/src/stm32flash_serial/src/utils.h b/macosx/src/stm32flash_serial/src/utils.h deleted file mode 100644 index a8d37d2d5..000000000 --- a/macosx/src/stm32flash_serial/src/utils.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _H_UTILS -#define _H_UTILS - -#include - -char cpu_le(); -uint32_t be_u32(const uint32_t v); -uint32_t le_u32(const uint32_t v); - -#endif diff --git a/win/src/stm32flash_serial/src/AUTHORS b/win/src/stm32flash_serial/src/AUTHORS deleted file mode 100644 index d096f2205..000000000 --- a/win/src/stm32flash_serial/src/AUTHORS +++ /dev/null @@ -1,19 +0,0 @@ -Authors ordered by first contribution. - -Geoffrey McRae -Bret Olmsted -Tormod Volden -Jakob Malm -Reuben Dowle -Matthias Kubisch -Paul Fertser -Daniel Strnad -Jérémie Rapin -Christian Pointner -Mats Erik Andersson -Alexey Borovik -Antonio Borneo -Armin van der Togt -Brian Silverman -Georg Hofmann -Luis Rodrigues diff --git a/win/src/stm32flash_serial/src/Android.mk b/win/src/stm32flash_serial/src/Android.mk deleted file mode 100644 index 7be3d0018..000000000 --- a/win/src/stm32flash_serial/src/Android.mk +++ /dev/null @@ -1,20 +0,0 @@ -TOP_LOCAL_PATH := $(call my-dir) - -include $(call all-named-subdir-makefiles, parsers) - -LOCAL_PATH := $(TOP_LOCAL_PATH) - -include $(CLEAR_VARS) -LOCAL_MODULE := stm32flash -LOCAL_SRC_FILES := \ - dev_table.c \ - i2c.c \ - init.c \ - main.c \ - port.c \ - serial_common.c \ - serial_platform.c \ - stm32.c \ - utils.c -LOCAL_STATIC_LIBRARIES := libparsers -include $(BUILD_EXECUTABLE) diff --git a/win/src/stm32flash_serial/src/HOWTO b/win/src/stm32flash_serial/src/HOWTO deleted file mode 100644 index d8f32eb04..000000000 --- a/win/src/stm32flash_serial/src/HOWTO +++ /dev/null @@ -1,35 +0,0 @@ -Add new interfaces: -===================================================================== -Current version 0.4 supports the following interfaces: -- UART Windows (either "COMn" and "\\.\COMn"); -- UART posix/Linux (e.g. "/dev/ttyUSB0"); -- I2C Linux through standard driver "i2c-dev" (e.g. "/dev/i2c-n"). - -Starting from version 0.4, the back-end of stm32flash is modular and -ready to be expanded to support new interfaces. -I'm planning adding SPI on Linux through standard driver "spidev". -You are invited to contribute with more interfaces. - -To add a new interface you need to add a new file, populate the struct -port_interface (check at the end of files i2c.c, serial_posix.c and -serial_w32.c) and provide the relative functions to operate on the -interface: open/close, read/write, get_cfg_str and the optional gpio. -The include the new drive in Makefile and register the new struct -port_interface in file port.c in struct port_interface *ports[]. - -There are several USB-I2C adapter in the market, each providing its -own libraries to communicate with the I2C bus. -Could be interesting to provide as back-end a bridge between stm32flash -and such libraries (I have no plan on this item). - - -Add new STM32 devices: -===================================================================== -Add a new line in file dev_table.c, in table devices[]. -The fields of the table are listed in stm32.h, struct stm32_dev. - - -Cross compile on Linux host for Windows target with MinGW: -===================================================================== -I'm using a 64 bit Arch Linux machines, and I usually run: - make CC=x86_64-w64-mingw32-gcc AR=x86_64-w64-mingw32-ar diff --git a/win/src/stm32flash_serial/src/I2C.txt b/win/src/stm32flash_serial/src/I2C.txt deleted file mode 100644 index 4c05ff62d..000000000 --- a/win/src/stm32flash_serial/src/I2C.txt +++ /dev/null @@ -1,94 +0,0 @@ -About I2C back-end communication in stm32flash -========================================================================== - -Starting from version v0.4, beside the serial communication port, -stm32flash adds support for I2C port to talk with STM32 bootloader. - -The current I2C back-end supports only the API provided by Linux kernel -driver "i2c-dev", so only I2C controllers with Linux kernel driver can be -used. -In Linux source code, most of the drivers for I2C and SMBUS controllers -are in - ./drivers/i2c/busses/ -Only I2C is supported by STM32 bootloader, so check the section below -about SMBUS. -No I2C support for Windows is available in stm32flash v0.4. - -Thanks to the new modular back-end, stm32flash can be easily extended to -support new back-ends and API. Check HOWTO file in stm32flash source code -for details. - -In the market there are several USB-to-I2C dongles; most of them are not -supported by kernel drivers. Manufacturer provide proprietary userspace -libraries using not standardized API. -These API and dongles could be supported in feature versions. - -There are currently 3 versions of STM32 bootloader for I2C communications: -- v1.0 using I2C clock stretching synchronization between host and STM32; -- v1.1 superset of v1.0, adds non stretching commands; -- v1.2 superset of v1.1, adds CRC command and compatibility with i2cdetect. -Details in ST application note AN2606. -All the bootloaders above are tested and working with stm32flash. - - -SMBUS controllers -========================================================================== - -Almost 50% of the drivers in Linux source code folder - ./drivers/i2c/busses/ -are for controllers that "only" support SMBUS protocol. They can NOT -operate with STM32 bootloader. -To identify if your controller supports I2C, use command: - i2cdetect -F n -where "n" is the number of the I2C interface (e.g. n=3 for "/dev/i2c-3"). -Controllers that supports I2C will report - I2C yes -Controller that support both I2C and SMBUS are ok. - -If you are interested on details about SMBUS protocol, you can download -the current specs from - http://smbus.org/specs/smbus20.pdf -and you can read the files in Linux source code - ./Documentation/i2c/i2c-protocol - ./Documentation/i2c/smbus-protocol - - -About bootloader v1.0 -========================================================================== - -Version v1.0 can have issues with some I2C controllers due to use of clock -stretching during commands that require long operations, like flash erase -and programming. - -Clock stretching is a technique to synchronize host and I2C device. When -I2C device wants to force a delay in the communication, it push "low" the -I2C clock; the I2C controller detects it and waits until I2C clock returns -"high". -Most I2C controllers set a "timeout" for clock stretching, ranging from -few milli-seconds to seconds depending on specific HW or SW driver. - -It is possible that the timeout in your I2C controller is smaller than the -delay required for flash erase or programming. In this case the I2C -controller will timeout and report error to stm32flash. -There is no possibility for stm32flash to retry, so it can only signal the -error and exit. - -To by-pass the issue with bootloader v1.0 you can modify the kernel driver -of your I2C controller. Not an easy job, since every controller has its own -way to handle the timeout. - -In my case I'm using the I2C controller integrated in the VGA port of my -laptop HP EliteBook 8460p. I built the 0.25$ VGA-to-I2C adapter reported in - http://www.paintyourdragon.com/?p=43 -To change the timeout of the I2C controller I had to modify the kernel file - drivers/gpu/drm/radeon/radeon_i2c.c -line 969 -- i2c->bit.timeout = usecs_to_jiffies(2200); /* from VESA */ -+ i2c->bit.timeout = msecs_to_jiffies(5000); /* 5s for STM32 */ -and recompile it. -Then - $> modprobe i2c-dev - $> chmod 666 /dev/i2c-7 - #> stm32flash -a 0x39 /dev/i2c-7 - -2014-09-16 Antonio Borneo diff --git a/win/src/stm32flash_serial/src/Makefile b/win/src/stm32flash_serial/src/Makefile deleted file mode 100644 index 0328d5588..000000000 --- a/win/src/stm32flash_serial/src/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -PREFIX = /usr/local -CFLAGS += -Wall -g - -INSTALL = install - -OBJS = dev_table.o \ - i2c.o \ - init.o \ - main.o \ - port.o \ - serial_common.o \ - serial_platform.o \ - stm32.o \ - utils.o - -LIBOBJS = parsers/parsers.a - -all: stm32flash - -serial_platform.o: serial_posix.c serial_w32.c - -parsers/parsers.a: - cd parsers && $(MAKE) parsers.a - -stm32flash: $(OBJS) $(LIBOBJS) - $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBOBJS) - -clean: - rm -f $(OBJS) stm32flash - cd parsers && $(MAKE) $@ - -install: all - $(INSTALL) -d $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -m 755 stm32flash $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -d $(DESTDIR)$(PREFIX)/share/man/man1 - $(INSTALL) -m 644 stm32flash.1 $(DESTDIR)$(PREFIX)/share/man/man1 - -.PHONY: all clean install diff --git a/win/src/stm32flash_serial/src/TODO b/win/src/stm32flash_serial/src/TODO deleted file mode 100644 index 41df614ff..000000000 --- a/win/src/stm32flash_serial/src/TODO +++ /dev/null @@ -1,7 +0,0 @@ - -stm32: -- Add support for variable page size - -AUTHORS: -- Add contributors from Geoffrey's commits - diff --git a/win/src/stm32flash_serial/src/dev_table.c b/win/src/stm32flash_serial/src/dev_table.c deleted file mode 100644 index 399cd9d08..000000000 --- a/win/src/stm32flash_serial/src/dev_table.c +++ /dev/null @@ -1,70 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "stm32.h" - -/* - * Device table, corresponds to the "Bootloader device-dependant parameters" - * table in ST document AN2606. - * Note that the option bytes upper range is inclusive! - */ -const stm32_dev_t devices[] = { - /* F0 */ - {0x440, "STM32F051xx" , 0x20001000, 0x20002000, 0x08000000, 0x08010000, 4, 1024, 0x1FFFF800, 0x1FFFF80B, 0x1FFFEC00, 0x1FFFF800}, - {0x444, "STM32F030/F031" , 0x20001000, 0x20002000, 0x08000000, 0x08010000, 4, 1024, 0x1FFFF800, 0x1FFFF80B, 0x1FFFEC00, 0x1FFFF800}, - {0x445, "STM32F042xx" , 0x20001800, 0x20001800, 0x08000000, 0x08008000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFC400, 0x1FFFF800}, - {0x448, "STM32F072xx" , 0x20001800, 0x20004000, 0x08000000, 0x08020000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFC800, 0x1FFFF800}, - /* F1 */ - {0x412, "Low-density" , 0x20000200, 0x20002800, 0x08000000, 0x08008000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x410, "Medium-density" , 0x20000200, 0x20005000, 0x08000000, 0x08020000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x414, "High-density" , 0x20000200, 0x20010000, 0x08000000, 0x08080000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x420, "Medium-density VL" , 0x20000200, 0x20002000, 0x08000000, 0x08020000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x428, "High-density VL" , 0x20000200, 0x20008000, 0x08000000, 0x08080000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x418, "Connectivity line" , 0x20001000, 0x20010000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFB000, 0x1FFFF800}, - {0x430, "XL-density" , 0x20000800, 0x20018000, 0x08000000, 0x08100000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFE000, 0x1FFFF800}, - /* Note that F2 and F4 devices have sectors of different page sizes - and only the first sectors (of one page size) are included here */ - /* F2 */ - {0x411, "STM32F2xx" , 0x20002000, 0x20020000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77DF}, - /* F3 */ - {0x432, "STM32F373/8" , 0x20001400, 0x20008000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - {0x422, "F302xB/303xB/358" , 0x20001400, 0x20010000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - {0x439, "STM32F302x4(6/8)" , 0x20001800, 0x20004000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - {0x438, "F303x4/334/328" , 0x20001800, 0x20003000, 0x08000000, 0x08040000, 2, 2048, 0x1FFFF800, 0x1FFFF80F, 0x1FFFD800, 0x1FFFF800}, - /* F4 */ - {0x413, "STM32F40/1" , 0x20002000, 0x20020000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77DF}, - /* 0x419 is also used for STM32F429/39 but with other bootloader ID... */ - {0x419, "STM32F427/37" , 0x20002000, 0x20030000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF}, - {0x423, "STM32F401xB(C)" , 0x20003000, 0x20010000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF}, - {0x433, "STM32F401xD(E)" , 0x20003000, 0x20018000, 0x08000000, 0x08100000, 4, 16384, 0x1FFFC000, 0x1FFFC00F, 0x1FFF0000, 0x1FFF77FF}, - /* L0 */ - {0x417, "L05xxx/06xxx" , 0x20001000, 0x20002000, 0x08000000, 0x08010000, 32, 128, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000}, - /* L1 */ - {0x416, "L1xxx6(8/B)" , 0x20000800, 0x20004000, 0x08000000, 0x08020000, 16, 256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000}, - {0x429, "L1xxx6(8/B)A" , 0x20001000, 0x20008000, 0x08000000, 0x08020000, 16, 256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF01000}, - {0x427, "L1xxxC" , 0x20001000, 0x20008000, 0x08000000, 0x08020000, 16, 256, 0x1FF80000, 0x1FF8000F, 0x1FF00000, 0x1FF02000}, - {0x436, "L1xxxD" , 0x20001000, 0x2000C000, 0x08000000, 0x08060000, 16, 256, 0x1ff80000, 0x1ff8000F, 0x1FF00000, 0x1FF02000}, - {0x437, "L1xxxE" , 0x20001000, 0x20014000, 0x08000000, 0x08060000, 16, 256, 0x1ff80000, 0x1ff8000F, 0x1FF00000, 0x1FF02000}, - /* These are not (yet) in AN2606: */ - {0x641, "Medium_Density PL" , 0x20000200, 0x00005000, 0x08000000, 0x08020000, 4, 1024, 0x1FFFF800, 0x1FFFF80F, 0x1FFFF000, 0x1FFFF800}, - {0x9a8, "STM32W-128K" , 0x20000200, 0x20002000, 0x08000000, 0x08020000, 1, 1024, 0, 0, 0, 0}, - {0x9b0, "STM32W-256K" , 0x20000200, 0x20004000, 0x08000000, 0x08040000, 1, 2048, 0, 0, 0, 0}, - {0x0} -}; diff --git a/win/src/stm32flash_serial/src/gpl-2.0.txt b/win/src/stm32flash_serial/src/gpl-2.0.txt deleted file mode 100644 index d159169d1..000000000 --- a/win/src/stm32flash_serial/src/gpl-2.0.txt +++ /dev/null @@ -1,339 +0,0 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 - - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. - - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. - - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. - - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. - - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. - - The precise terms and conditions for copying, distribution and -modification follow. - - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". - -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. - - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. - -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. - - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. - - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. - - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. - -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: - - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, - - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, - - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) - -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. - -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. - - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. - - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. - - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. - - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - 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 2 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, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - , 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. diff --git a/win/src/stm32flash_serial/src/i2c.c b/win/src/stm32flash_serial/src/i2c.c deleted file mode 100644 index 10e6bb15a..000000000 --- a/win/src/stm32flash_serial/src/i2c.c +++ /dev/null @@ -1,209 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "serial.h" -#include "port.h" - - -#if !defined(__linux__) - -static port_err_t i2c_open(struct port_interface *port, - struct port_options *ops) -{ - return PORT_ERR_NODEV; -} - -struct port_interface port_i2c = { - .name = "i2c", - .open = i2c_open, -}; - -#else - -#ifdef __ANDROID__ -#define I2C_SLAVE 0x0703 /* Use this slave address */ -#define I2C_FUNCS 0x0705 /* Get the adapter functionality mask */ -/* To determine what functionality is present */ -#define I2C_FUNC_I2C 0x00000001 -#else -#include -#include -#endif - -#include - -struct i2c_priv { - int fd; - int addr; -}; - -static port_err_t i2c_open(struct port_interface *port, - struct port_options *ops) -{ - struct i2c_priv *h; - int fd, addr, ret; - unsigned long funcs; - - /* 1. check device name match */ - if (strncmp(ops->device, "/dev/i2c-", strlen("/dev/i2c-"))) - return PORT_ERR_NODEV; - - /* 2. check options */ - addr = ops->bus_addr; - if (addr < 0x03 || addr > 0x77) { - fprintf(stderr, "I2C address out of range [0x03-0x77]\n"); - return PORT_ERR_UNKNOWN; - } - - /* 3. open it */ - h = calloc(sizeof(*h), 1); - if (h == NULL) { - fprintf(stderr, "End of memory\n"); - return PORT_ERR_UNKNOWN; - } - fd = open(ops->device, O_RDWR); - if (fd < 0) { - fprintf(stderr, "Unable to open special file \"%s\"\n", - ops->device); - free(h); - return PORT_ERR_UNKNOWN; - } - - /* 3.5. Check capabilities */ - ret = ioctl(fd, I2C_FUNCS, &funcs); - if (ret < 0) { - fprintf(stderr, "I2C ioctl(funcs) error %d\n", errno); - close(fd); - free(h); - return PORT_ERR_UNKNOWN; - } - if ((funcs & I2C_FUNC_I2C) == 0) { - fprintf(stderr, "Error: controller is not I2C, only SMBUS.\n"); - close(fd); - free(h); - return PORT_ERR_UNKNOWN; - } - - /* 4. set options */ - ret = ioctl(fd, I2C_SLAVE, addr); - if (ret < 0) { - fprintf(stderr, "I2C ioctl(slave) error %d\n", errno); - close(fd); - free(h); - return PORT_ERR_UNKNOWN; - } - - h->fd = fd; - h->addr = addr; - port->private = h; - return PORT_ERR_OK; -} - -static port_err_t i2c_close(struct port_interface *port) -{ - struct i2c_priv *h; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - close(h->fd); - free(h); - port->private = NULL; - return PORT_ERR_OK; -} - -static port_err_t i2c_read(struct port_interface *port, void *buf, - size_t nbyte) -{ - struct i2c_priv *h; - int ret; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - ret = read(h->fd, buf, nbyte); - if (ret != nbyte) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; -} - -static port_err_t i2c_write(struct port_interface *port, void *buf, - size_t nbyte) -{ - struct i2c_priv *h; - int ret; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - ret = write(h->fd, buf, nbyte); - if (ret != nbyte) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; -} - -static port_err_t i2c_gpio(struct port_interface *port, serial_gpio_t n, - int level) -{ - return PORT_ERR_OK; -} - -static const char *i2c_get_cfg_str(struct port_interface *port) -{ - struct i2c_priv *h; - static char str[11]; - - h = (struct i2c_priv *)port->private; - if (h == NULL) - return "INVALID"; - snprintf(str, sizeof(str), "addr 0x%2x", h->addr); - return str; -} - -static struct varlen_cmd i2c_cmd_get_reply[] = { - {0x10, 11}, - {0x11, 17}, - {0x12, 18}, - { /* sentinel */ } -}; - -struct port_interface port_i2c = { - .name = "i2c", - .flags = PORT_STRETCH_W, - .open = i2c_open, - .close = i2c_close, - .read = i2c_read, - .write = i2c_write, - .gpio = i2c_gpio, - .cmd_get_reply = i2c_cmd_get_reply, - .get_cfg_str = i2c_get_cfg_str, -}; - -#endif diff --git a/win/src/stm32flash_serial/src/init.c b/win/src/stm32flash_serial/src/init.c deleted file mode 100644 index 77a571bd8..000000000 --- a/win/src/stm32flash_serial/src/init.c +++ /dev/null @@ -1,219 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2013 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include -#include -#include "init.h" -#include "serial.h" -#include "stm32.h" -#include "port.h" - -struct gpio_list { - struct gpio_list *next; - int gpio; -}; - - -static int write_to(const char *filename, const char *value) -{ - int fd, ret; - - fd = open(filename, O_WRONLY); - if (fd < 0) { - fprintf(stderr, "Cannot open file \"%s\"\n", filename); - return 0; - } - ret = write(fd, value, strlen(value)); - if (ret < 0) { - fprintf(stderr, "Error writing in file \"%s\"\n", filename); - close(fd); - return 0; - } - close(fd); - return 1; -} - -#if !defined(__linux__) -static int drive_gpio(int n, int level, struct gpio_list **gpio_to_release) -{ - fprintf(stderr, "GPIO control only available in Linux\n"); - return 0; -} -#else -static int drive_gpio(int n, int level, struct gpio_list **gpio_to_release) -{ - char num[16]; /* sized to carry MAX_INT */ - char file[48]; /* sized to carry longest filename */ - struct stat buf; - struct gpio_list *new; - int ret; - - sprintf(file, "/sys/class/gpio/gpio%d/direction", n); - ret = stat(file, &buf); - if (ret) { - /* file miss, GPIO not exported yet */ - sprintf(num, "%d", n); - ret = write_to("/sys/class/gpio/export", num); - if (!ret) - return 0; - ret = stat(file, &buf); - if (ret) { - fprintf(stderr, "GPIO %d not available\n", n); - return 0; - } - new = (struct gpio_list *)malloc(sizeof(struct gpio_list)); - if (new == NULL) { - fprintf(stderr, "Out of memory\n"); - return 0; - } - new->gpio = n; - new->next = *gpio_to_release; - *gpio_to_release = new; - } - - return write_to(file, level ? "high" : "low"); -} -#endif - -static int release_gpio(int n) -{ - char num[16]; /* sized to carry MAX_INT */ - - sprintf(num, "%d", n); - return write_to("/sys/class/gpio/unexport", num); -} - -static int gpio_sequence(struct port_interface *port, const char *s, size_t l) -{ - struct gpio_list *gpio_to_release = NULL, *to_free; - int ret, level, gpio; - - ret = 1; - while (ret == 1 && *s && l > 0) { - if (*s == '-') { - level = 0; - s++; - l--; - } else - level = 1; - - if (isdigit(*s)) { - gpio = atoi(s); - while (isdigit(*s)) { - s++; - l--; - } - } else if (!strncmp(s, "rts", 3)) { - gpio = -GPIO_RTS; - s += 3; - l -= 3; - } else if (!strncmp(s, "dtr", 3)) { - gpio = -GPIO_DTR; - s += 3; - l -= 3; - } else if (!strncmp(s, "brk", 3)) { - gpio = -GPIO_BRK; - s += 3; - l -= 3; - } else { - fprintf(stderr, "Character \'%c\' is not a digit\n", *s); - ret = 0; - break; - } - - if (*s && (l > 0)) { - if (*s == ',') { - s++; - l--; - } else { - fprintf(stderr, "Character \'%c\' is not a separator\n", *s); - ret = 0; - break; - } - } - if (gpio < 0) - ret = (port->gpio(port, -gpio, level) == PORT_ERR_OK); - else - ret = drive_gpio(gpio, level, &gpio_to_release); - usleep(100000); - } - - while (gpio_to_release) { - release_gpio(gpio_to_release->gpio); - to_free = gpio_to_release; - gpio_to_release = gpio_to_release->next; - free(to_free); - } - usleep(500000); - return ret; -} - -static int gpio_bl_entry(struct port_interface *port, const char *seq) -{ - char *s; - - if (seq == NULL || seq[0] == ':') - return 1; - - s = strchr(seq, ':'); - if (s == NULL) - return gpio_sequence(port, seq, strlen(seq)); - - return gpio_sequence(port, seq, s - seq); -} - -static int gpio_bl_exit(struct port_interface *port, const char *seq) -{ - char *s; - - if (seq == NULL) - return 1; - - s = strchr(seq, ':'); - if (s == NULL || s[1] == '\0') - return 1; - - return gpio_sequence(port, s + 1, strlen(s + 1)); -} - -int init_bl_entry(struct port_interface *port, const char *seq) -{ - if (seq) - return gpio_bl_entry(port, seq); - - return 1; -} - -int init_bl_exit(stm32_t *stm, struct port_interface *port, const char *seq) -{ - if (seq) - return gpio_bl_exit(port, seq); - - if (stm32_reset_device(stm) != STM32_ERR_OK) - return 0; - return 1; -} diff --git a/win/src/stm32flash_serial/src/init.h b/win/src/stm32flash_serial/src/init.h deleted file mode 100644 index 6075b519b..000000000 --- a/win/src/stm32flash_serial/src/init.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2013 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _INIT_H -#define _INIT_H - -#include "stm32.h" -#include "port.h" - -int init_bl_entry(struct port_interface *port, const char *seq); -int init_bl_exit(stm32_t *stm, struct port_interface *port, const char *seq); - -#endif diff --git a/win/src/stm32flash_serial/src/main.c b/win/src/stm32flash_serial/src/main.c deleted file mode 100644 index f081d6131..000000000 --- a/win/src/stm32flash_serial/src/main.c +++ /dev/null @@ -1,774 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright 2010 Geoffrey McRae - Copyright 2011 Steve Markgraf - Copyright 2012 Tormod Volden - Copyright 2013 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include - -#include "init.h" -#include "utils.h" -#include "serial.h" -#include "stm32.h" -#include "parsers/parser.h" -#include "port.h" - -#include "parsers/binary.h" -#include "parsers/hex.h" - -#define VERSION "Arduino_STM32_0.9" - -/* device globals */ -stm32_t *stm = NULL; - -void *p_st = NULL; -parser_t *parser = NULL; - -/* settings */ -struct port_options port_opts = { - .device = NULL, - .baudRate = SERIAL_BAUD_57600, - .serial_mode = "8e1", - .bus_addr = 0, - .rx_frame_max = STM32_MAX_RX_FRAME, - .tx_frame_max = STM32_MAX_TX_FRAME, -}; -int rd = 0; -int wr = 0; -int wu = 0; -int rp = 0; -int ur = 0; -int eraseOnly = 0; -int crc = 0; -int npages = 0; -int spage = 0; -int no_erase = 0; -char verify = 0; -int retry = 10; -char exec_flag = 0; -uint32_t execute = 0; -char init_flag = 1; -char force_binary = 0; -char reset_flag = 0; -char *filename; -char *gpio_seq = NULL; -uint32_t start_addr = 0; -uint32_t readwrite_len = 0; - -/* functions */ -int parse_options(int argc, char *argv[]); -void show_help(char *name); - -static int is_addr_in_ram(uint32_t addr) -{ - return addr >= stm->dev->ram_start && addr < stm->dev->ram_end; -} - -static int is_addr_in_flash(uint32_t addr) -{ - return addr >= stm->dev->fl_start && addr < stm->dev->fl_end; -} - -static int flash_addr_to_page_floor(uint32_t addr) -{ - if (!is_addr_in_flash(addr)) - return 0; - - return (addr - stm->dev->fl_start) / stm->dev->fl_ps; -} - -static int flash_addr_to_page_ceil(uint32_t addr) -{ - if (!(addr >= stm->dev->fl_start && addr <= stm->dev->fl_end)) - return 0; - - return (addr + stm->dev->fl_ps - 1 - stm->dev->fl_start) - / stm->dev->fl_ps; -} - -static uint32_t flash_page_to_addr(int page) -{ - return stm->dev->fl_start + page * stm->dev->fl_ps; -} - -int main(int argc, char* argv[]) { - struct port_interface *port = NULL; - int ret = 1; - stm32_err_t s_err; - parser_err_t perr; - FILE *diag = stdout; - - fprintf(diag, "stm32flash " VERSION "\n\n"); - fprintf(diag, "http://github.com/rogerclarkmelbourne/arduino_stm32\n\n"); - if (parse_options(argc, argv) != 0) - goto close; - - if (rd && filename[0] == '-') { - diag = stderr; - } - - if (wr) { - /* first try hex */ - if (!force_binary) { - parser = &PARSER_HEX; - p_st = parser->init(); - if (!p_st) { - fprintf(stderr, "%s Parser failed to initialize\n", parser->name); - goto close; - } - } - - if (force_binary || (perr = parser->open(p_st, filename, 0)) != PARSER_ERR_OK) { - if (force_binary || perr == PARSER_ERR_INVALID_FILE) { - if (!force_binary) { - parser->close(p_st); - p_st = NULL; - } - - /* now try binary */ - parser = &PARSER_BINARY; - p_st = parser->init(); - if (!p_st) { - fprintf(stderr, "%s Parser failed to initialize\n", parser->name); - goto close; - } - perr = parser->open(p_st, filename, 0); - } - - /* if still have an error, fail */ - if (perr != PARSER_ERR_OK) { - fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr)); - if (perr == PARSER_ERR_SYSTEM) perror(filename); - goto close; - } - } - - fprintf(diag, "Using Parser : %s\n", parser->name); - } else { - parser = &PARSER_BINARY; - p_st = parser->init(); - if (!p_st) { - fprintf(stderr, "%s Parser failed to initialize\n", parser->name); - goto close; - } - } - - if (port_open(&port_opts, &port) != PORT_ERR_OK) { - fprintf(stderr, "Failed to open port: %s\n", port_opts.device); - goto close; - } - - fprintf(diag, "Interface %s: %s\n", port->name, port->get_cfg_str(port)); - if (init_flag && init_bl_entry(port, gpio_seq) == 0) - goto close; - stm = stm32_init(port, init_flag); - if (!stm) - goto close; - - fprintf(diag, "Version : 0x%02x\n", stm->bl_version); - if (port->flags & PORT_GVR_ETX) { - fprintf(diag, "Option 1 : 0x%02x\n", stm->option1); - fprintf(diag, "Option 2 : 0x%02x\n", stm->option2); - } - fprintf(diag, "Device ID : 0x%04x (%s)\n", stm->pid, stm->dev->name); - fprintf(diag, "- RAM : %dKiB (%db reserved by bootloader)\n", (stm->dev->ram_end - 0x20000000) / 1024, stm->dev->ram_start - 0x20000000); - fprintf(diag, "- Flash : %dKiB (sector size: %dx%d)\n", (stm->dev->fl_end - stm->dev->fl_start ) / 1024, stm->dev->fl_pps, stm->dev->fl_ps); - fprintf(diag, "- Option RAM : %db\n", stm->dev->opt_end - stm->dev->opt_start + 1); - fprintf(diag, "- System RAM : %dKiB\n", (stm->dev->mem_end - stm->dev->mem_start) / 1024); - - uint8_t buffer[256]; - uint32_t addr, start, end; - unsigned int len; - int failed = 0; - int first_page, num_pages; - - /* - * Cleanup addresses: - * - * Starting from options - * start_addr, readwrite_len, spage, npages - * and using device memory size, compute - * start, end, first_page, num_pages - */ - if (start_addr || readwrite_len) { - start = start_addr; - - if (is_addr_in_flash(start)) - end = stm->dev->fl_end; - else { - no_erase = 1; - if (is_addr_in_ram(start)) - end = stm->dev->ram_end; - else - end = start + sizeof(uint32_t); - } - - if (readwrite_len && (end > start + readwrite_len)) - end = start + readwrite_len; - - first_page = flash_addr_to_page_floor(start); - if (!first_page && end == stm->dev->fl_end) - num_pages = 0xff; /* mass erase */ - else - num_pages = flash_addr_to_page_ceil(end) - first_page; - } else if (!spage && !npages) { - start = stm->dev->fl_start; - end = stm->dev->fl_end; - first_page = 0; - num_pages = 0xff; /* mass erase */ - } else { - first_page = spage; - start = flash_page_to_addr(first_page); - if (start > stm->dev->fl_end) { - fprintf(stderr, "Address range exceeds flash size.\n"); - goto close; - } - - if (npages) { - num_pages = npages; - end = flash_page_to_addr(first_page + num_pages); - if (end > stm->dev->fl_end) - end = stm->dev->fl_end; - } else { - end = stm->dev->fl_end; - num_pages = flash_addr_to_page_ceil(end) - first_page; - } - - if (!first_page && end == stm->dev->fl_end) - num_pages = 0xff; /* mass erase */ - } - - if (rd) { - unsigned int max_len = port_opts.rx_frame_max; - - fprintf(diag, "Memory read\n"); - - perr = parser->open(p_st, filename, 1); - if (perr != PARSER_ERR_OK) { - fprintf(stderr, "%s ERROR: %s\n", parser->name, parser_errstr(perr)); - if (perr == PARSER_ERR_SYSTEM) - perror(filename); - goto close; - } - - fflush(diag); - addr = start; - while(addr < end) { - uint32_t left = end - addr; - len = max_len > left ? left : max_len; - s_err = stm32_read_memory(stm, addr, buffer, len); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to read memory at address 0x%08x, target write-protected?\n", addr); - goto close; - } - if (parser->write(p_st, buffer, len) != PARSER_ERR_OK) - { - fprintf(stderr, "Failed to write data to file\n"); - goto close; - } - addr += len; - - fprintf(diag, - "\rRead address 0x%08x (%.2f%%) ", - addr, - (100.0f / (float)(end - start)) * (float)(addr - start) - ); - fflush(diag); - } - fprintf(diag, "Done.\n"); - ret = 0; - goto close; - } else if (rp) { - fprintf(stdout, "Read-Protecting flash\n"); - /* the device automatically performs a reset after the sending the ACK */ - reset_flag = 0; - stm32_readprot_memory(stm); - fprintf(stdout, "Done.\n"); - } else if (ur) { - fprintf(stdout, "Read-UnProtecting flash\n"); - /* the device automatically performs a reset after the sending the ACK */ - reset_flag = 0; - stm32_runprot_memory(stm); - fprintf(stdout, "Done.\n"); - } else if (eraseOnly) { - ret = 0; - fprintf(stdout, "Erasing flash\n"); - - if (num_pages != 0xff && - (start != flash_page_to_addr(first_page) - || end != flash_page_to_addr(first_page + num_pages))) { - fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n"); - ret = 1; - goto close; - } - - s_err = stm32_erase_memory(stm, first_page, num_pages); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to erase memory\n"); - ret = 1; - goto close; - } - } else if (wu) { - fprintf(diag, "Write-unprotecting flash\n"); - /* the device automatically performs a reset after the sending the ACK */ - reset_flag = 0; - stm32_wunprot_memory(stm); - fprintf(diag, "Done.\n"); - - } else if (wr) { - fprintf(diag, "Write to memory\n"); - - off_t offset = 0; - ssize_t r; - unsigned int size; - unsigned int max_wlen, max_rlen; - - max_wlen = port_opts.tx_frame_max - 2; /* skip len and crc */ - max_wlen &= ~3; /* 32 bit aligned */ - - max_rlen = port_opts.rx_frame_max; - max_rlen = max_rlen < max_wlen ? max_rlen : max_wlen; - - /* Assume data from stdin is whole device */ - if (filename[0] == '-' && filename[1] == '\0') - size = end - start; - else - size = parser->size(p_st); - - // TODO: It is possible to write to non-page boundaries, by reading out flash - // from partial pages and combining with the input data - // if ((start % stm->dev->fl_ps) != 0 || (end % stm->dev->fl_ps) != 0) { - // fprintf(stderr, "Specified start & length are invalid (must be page aligned)\n"); - // goto close; - // } - - // TODO: If writes are not page aligned, we should probably read out existing flash - // contents first, so it can be preserved and combined with new data - if (!no_erase && num_pages) { - fprintf(diag, "Erasing memory\n"); - s_err = stm32_erase_memory(stm, first_page, num_pages); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to erase memory\n"); - goto close; - } - } - - fflush(diag); - addr = start; - while(addr < end && offset < size) { - uint32_t left = end - addr; - len = max_wlen > left ? left : max_wlen; - len = len > size - offset ? size - offset : len; - - if (parser->read(p_st, buffer, &len) != PARSER_ERR_OK) - goto close; - - if (len == 0) { - if (filename[0] == '-') { - break; - } else { - fprintf(stderr, "Failed to read input file\n"); - goto close; - } - } - - again: - s_err = stm32_write_memory(stm, addr, buffer, len); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to write memory at address 0x%08x\n", addr); - goto close; - } - - if (verify) { - uint8_t compare[len]; - unsigned int offset, rlen; - - offset = 0; - while (offset < len) { - rlen = len - offset; - rlen = rlen < max_rlen ? rlen : max_rlen; - s_err = stm32_read_memory(stm, addr + offset, compare + offset, rlen); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to read memory at address 0x%08x\n", addr + offset); - goto close; - } - offset += rlen; - } - - for(r = 0; r < len; ++r) - if (buffer[r] != compare[r]) { - if (failed == retry) { - fprintf(stderr, "Failed to verify at address 0x%08x, expected 0x%02x and found 0x%02x\n", - (uint32_t)(addr + r), - buffer [r], - compare[r] - ); - goto close; - } - ++failed; - goto again; - } - - failed = 0; - } - - addr += len; - offset += len; - - fprintf(diag, - "\rWrote %saddress 0x%08x (%.2f%%) ", - verify ? "and verified " : "", - addr, - (100.0f / size) * offset - ); - fflush(diag); - - } - - fprintf(diag, "Done.\n"); - ret = 0; - goto close; - } else if (crc) { - uint32_t crc_val = 0; - - fprintf(diag, "CRC computation\n"); - - s_err = stm32_crc_wrapper(stm, start, end - start, &crc_val); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Failed to read CRC\n"); - goto close; - } - fprintf(diag, "CRC(0x%08x-0x%08x) = 0x%08x\n", start, end, - crc_val); - ret = 0; - goto close; - } else - ret = 0; - -close: - if (stm && exec_flag && ret == 0) { - if (execute == 0) - execute = stm->dev->fl_start; - - fprintf(diag, "\nStarting execution at address 0x%08x... ", execute); - fflush(diag); - if (stm32_go(stm, execute) == STM32_ERR_OK) { - reset_flag = 0; - fprintf(diag, "done.\n"); - } else - fprintf(diag, "failed.\n"); - } - - if (stm && reset_flag) { - fprintf(diag, "\nResetting device... "); - fflush(diag); - if (init_bl_exit(stm, port, gpio_seq)) - fprintf(diag, "done.\n"); - else fprintf(diag, "failed.\n"); - } - - if (p_st ) parser->close(p_st); - if (stm ) stm32_close (stm); - if (port) - port->close(port); - - fprintf(diag, "\n"); - return ret; -} - -int parse_options(int argc, char *argv[]) -{ - int c; - char *pLen; - - while ((c = getopt(argc, argv, "a:b:m:r:w:e:vn:g:jkfcChuos:S:F:i:R")) != -1) { - switch(c) { - case 'a': - port_opts.bus_addr = strtoul(optarg, NULL, 0); - break; - - case 'b': - port_opts.baudRate = serial_get_baud(strtoul(optarg, NULL, 0)); - if (port_opts.baudRate == SERIAL_BAUD_INVALID) { - serial_baud_t baudrate; - fprintf(stderr, "Invalid baud rate, valid options are:\n"); - for (baudrate = SERIAL_BAUD_1200; baudrate != SERIAL_BAUD_INVALID; ++baudrate) - fprintf(stderr, " %d\n", serial_get_baud_int(baudrate)); - return 1; - } - break; - - case 'm': - if (strlen(optarg) != 3 - || serial_get_bits(optarg) == SERIAL_BITS_INVALID - || serial_get_parity(optarg) == SERIAL_PARITY_INVALID - || serial_get_stopbit(optarg) == SERIAL_STOPBIT_INVALID) { - fprintf(stderr, "Invalid serial mode\n"); - return 1; - } - port_opts.serial_mode = optarg; - break; - - case 'r': - case 'w': - rd = rd || c == 'r'; - wr = wr || c == 'w'; - if (rd && wr) { - fprintf(stderr, "ERROR: Invalid options, can't read & write at the same time\n"); - return 1; - } - filename = optarg; - if (filename[0] == '-') { - force_binary = 1; - } - break; - case 'e': - if (readwrite_len || start_addr) { - fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n"); - return 1; - } - npages = strtoul(optarg, NULL, 0); - if (npages > 0xFF || npages < 0) { - fprintf(stderr, "ERROR: You need to specify a page count between 0 and 255"); - return 1; - } - if (!npages) - no_erase = 1; - break; - case 'u': - wu = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't write unprotect and read/write at the same time\n"); - return 1; - } - break; - - case 'j': - rp = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't read protect and read/write at the same time\n"); - return 1; - } - break; - - case 'k': - ur = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't read unprotect and read/write at the same time\n"); - return 1; - } - break; - - case 'o': - eraseOnly = 1; - if (rd || wr) { - fprintf(stderr, "ERROR: Invalid options, can't erase-only and read/write at the same time\n"); - return 1; - } - break; - - case 'v': - verify = 1; - break; - - case 'n': - retry = strtoul(optarg, NULL, 0); - break; - - case 'g': - exec_flag = 1; - execute = strtoul(optarg, NULL, 0); - if (execute % 4 != 0) { - fprintf(stderr, "ERROR: Execution address must be word-aligned\n"); - return 1; - } - break; - case 's': - if (readwrite_len || start_addr) { - fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n"); - return 1; - } - spage = strtoul(optarg, NULL, 0); - break; - case 'S': - if (spage || npages) { - fprintf(stderr, "ERROR: Invalid options, can't specify start page / num pages and start address/length\n"); - return 1; - } else { - start_addr = strtoul(optarg, &pLen, 0); - if (*pLen == ':') { - pLen++; - readwrite_len = strtoul(pLen, NULL, 0); - if (readwrite_len == 0) { - fprintf(stderr, "ERROR: Invalid options, can't specify zero length\n"); - return 1; - } - } - } - break; - case 'F': - port_opts.rx_frame_max = strtoul(optarg, &pLen, 0); - if (*pLen == ':') { - pLen++; - port_opts.tx_frame_max = strtoul(pLen, NULL, 0); - } - if (port_opts.rx_frame_max < 0 - || port_opts.tx_frame_max < 0) { - fprintf(stderr, "ERROR: Invalid negative value for option -F\n"); - return 1; - } - if (port_opts.rx_frame_max == 0) - port_opts.rx_frame_max = STM32_MAX_RX_FRAME; - if (port_opts.tx_frame_max == 0) - port_opts.tx_frame_max = STM32_MAX_TX_FRAME; - if (port_opts.rx_frame_max < 20 - || port_opts.tx_frame_max < 5) { - fprintf(stderr, "ERROR: current code cannot work with small frames.\n"); - fprintf(stderr, "min(RX) = 20, min(TX) = 5\n"); - return 1; - } - if (port_opts.rx_frame_max > STM32_MAX_RX_FRAME) { - fprintf(stderr, "WARNING: Ignore RX length in option -F\n"); - port_opts.rx_frame_max = STM32_MAX_RX_FRAME; - } - if (port_opts.tx_frame_max > STM32_MAX_TX_FRAME) { - fprintf(stderr, "WARNING: Ignore TX length in option -F\n"); - port_opts.tx_frame_max = STM32_MAX_TX_FRAME; - } - break; - case 'f': - force_binary = 1; - break; - - case 'c': - init_flag = 0; - break; - - case 'h': - show_help(argv[0]); - exit(0); - - case 'i': - gpio_seq = optarg; - break; - - case 'R': - reset_flag = 1; - break; - - case 'C': - crc = 1; - break; - } - } - - for (c = optind; c < argc; ++c) { - if (port_opts.device) { - fprintf(stderr, "ERROR: Invalid parameter specified\n"); - show_help(argv[0]); - return 1; - } - port_opts.device = argv[c]; - } - - if (port_opts.device == NULL) { - fprintf(stderr, "ERROR: Device not specified\n"); - show_help(argv[0]); - return 1; - } - - if (!wr && verify) { - fprintf(stderr, "ERROR: Invalid usage, -v is only valid when writing\n"); - show_help(argv[0]); - return 1; - } - - return 0; -} - -void show_help(char *name) { - fprintf(stderr, - "Usage: %s [-bvngfhc] [-[rw] filename] [tty_device | i2c_device]\n" - " -a bus_address Bus address (e.g. for I2C port)\n" - " -b rate Baud rate (default 57600)\n" - " -m mode Serial port mode (default 8e1)\n" - " -r filename Read flash to file (or - stdout)\n" - " -w filename Write flash from file (or - stdout)\n" - " -C Compute CRC of flash content\n" - " -u Disable the flash write-protection\n" - " -j Enable the flash read-protection\n" - " -k Disable the flash read-protection\n" - " -o Erase only\n" - " -e n Only erase n pages before writing the flash\n" - " -v Verify writes\n" - " -n count Retry failed writes up to count times (default 10)\n" - " -g address Start execution at specified address (0 = flash start)\n" - " -S address[:length] Specify start address and optionally length for\n" - " read/write/erase operations\n" - " -F RX_length[:TX_length] Specify the max length of RX and TX frame\n" - " -s start_page Flash at specified page (0 = flash start)\n" - " -f Force binary parser\n" - " -h Show this help\n" - " -c Resume the connection (don't send initial INIT)\n" - " *Baud rate must be kept the same as the first init*\n" - " This is useful if the reset fails\n" - " -i GPIO_string GPIO sequence to enter/exit bootloader mode\n" - " GPIO_string=[entry_seq][:[exit_seq]]\n" - " sequence=[-]n[,sequence]\n" - " -R Reset device at exit.\n" - "\n" - "Examples:\n" - " Get device information:\n" - " %s /dev/ttyS0\n" - " or:\n" - " %s /dev/i2c-0\n" - "\n" - " Write with verify and then start execution:\n" - " %s -w filename -v -g 0x0 /dev/ttyS0\n" - "\n" - " Read flash to file:\n" - " %s -r filename /dev/ttyS0\n" - "\n" - " Read 100 bytes of flash from 0x1000 to stdout:\n" - " %s -r - -S 0x1000:100 /dev/ttyS0\n" - "\n" - " Start execution:\n" - " %s -g 0x0 /dev/ttyS0\n" - "\n" - " GPIO sequence:\n" - " - entry sequence: GPIO_3=low, GPIO_2=low, GPIO_2=high\n" - " - exit sequence: GPIO_3=high, GPIO_2=low, GPIO_2=high\n" - " %s -i -3,-2,2:3,-2,2 /dev/ttyS0\n", - name, - name, - name, - name, - name, - name, - name, - name - ); -} - diff --git a/win/src/stm32flash_serial/src/parsers/Android.mk b/win/src/stm32flash_serial/src/parsers/Android.mk deleted file mode 100644 index afec18cd5..000000000 --- a/win/src/stm32flash_serial/src/parsers/Android.mk +++ /dev/null @@ -1,6 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := libparsers -LOCAL_SRC_FILES := binary.c hex.c -include $(BUILD_STATIC_LIBRARY) diff --git a/win/src/stm32flash_serial/src/parsers/Makefile b/win/src/stm32flash_serial/src/parsers/Makefile deleted file mode 100644 index bb7df1e02..000000000 --- a/win/src/stm32flash_serial/src/parsers/Makefile +++ /dev/null @@ -1,12 +0,0 @@ - -CFLAGS += -Wall -g - -all: parsers.a - -parsers.a: binary.o hex.o - $(AR) rc $@ binary.o hex.o - -clean: - rm -f *.o parsers.a - -.PHONY: all clean diff --git a/win/src/stm32flash_serial/src/parsers/binary.c b/win/src/stm32flash_serial/src/parsers/binary.c deleted file mode 100644 index f491952bb..000000000 --- a/win/src/stm32flash_serial/src/parsers/binary.c +++ /dev/null @@ -1,140 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include - -#include "binary.h" - -typedef struct { - int fd; - char write; - struct stat stat; -} binary_t; - -void* binary_init() { - return calloc(sizeof(binary_t), 1); -} - -parser_err_t binary_open(void *storage, const char *filename, const char write) { - binary_t *st = storage; - if (write) { - if (filename[0] == '-') - st->fd = 1; - else - st->fd = open( - filename, -#ifndef __WIN32__ - O_WRONLY | O_CREAT | O_TRUNC, -#else - O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, -#endif -#ifndef __WIN32__ - S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH -#else - 0 -#endif - ); - st->stat.st_size = 0; - } else { - if (filename[0] == '-') { - st->fd = 0; - } else { - if (stat(filename, &st->stat) != 0) - return PARSER_ERR_INVALID_FILE; - st->fd = open(filename, -#ifndef __WIN32__ - O_RDONLY -#else - O_RDONLY | O_BINARY -#endif - ); - } - } - - st->write = write; - return st->fd == -1 ? PARSER_ERR_SYSTEM : PARSER_ERR_OK; -} - -parser_err_t binary_close(void *storage) { - binary_t *st = storage; - - if (st->fd) close(st->fd); - free(st); - return PARSER_ERR_OK; -} - -unsigned int binary_size(void *storage) { - binary_t *st = storage; - return st->stat.st_size; -} - -parser_err_t binary_read(void *storage, void *data, unsigned int *len) { - binary_t *st = storage; - unsigned int left = *len; - if (st->write) return PARSER_ERR_WRONLY; - - ssize_t r; - while(left > 0) { - r = read(st->fd, data, left); - /* If there is no data to read at all, return OK, but with zero read */ - if (r == 0 && left == *len) { - *len = 0; - return PARSER_ERR_OK; - } - if (r <= 0) return PARSER_ERR_SYSTEM; - left -= r; - data += r; - } - - *len = *len - left; - return PARSER_ERR_OK; -} - -parser_err_t binary_write(void *storage, void *data, unsigned int len) { - binary_t *st = storage; - if (!st->write) return PARSER_ERR_RDONLY; - - ssize_t r; - while(len > 0) { - r = write(st->fd, data, len); - if (r < 1) return PARSER_ERR_SYSTEM; - st->stat.st_size += r; - - len -= r; - data += r; - } - - return PARSER_ERR_OK; -} - -parser_t PARSER_BINARY = { - "Raw BINARY", - binary_init, - binary_open, - binary_close, - binary_size, - binary_read, - binary_write -}; - diff --git a/win/src/stm32flash_serial/src/parsers/binary.h b/win/src/stm32flash_serial/src/parsers/binary.h deleted file mode 100644 index d989acfa0..000000000 --- a/win/src/stm32flash_serial/src/parsers/binary.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _PARSER_BINARY_H -#define _PARSER_BINARY_H - -#include "parser.h" - -extern parser_t PARSER_BINARY; -#endif diff --git a/win/src/stm32flash_serial/src/parsers/hex.c b/win/src/stm32flash_serial/src/parsers/hex.c deleted file mode 100644 index 3baf85623..000000000 --- a/win/src/stm32flash_serial/src/parsers/hex.c +++ /dev/null @@ -1,224 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#include -#include -#include -#include -#include -#include -#include - -#include "hex.h" -#include "../utils.h" - -typedef struct { - size_t data_len, offset; - uint8_t *data; - uint8_t base; -} hex_t; - -void* hex_init() { - return calloc(sizeof(hex_t), 1); -} - -parser_err_t hex_open(void *storage, const char *filename, const char write) { - hex_t *st = storage; - if (write) { - return PARSER_ERR_RDONLY; - } else { - char mark; - int i, fd; - uint8_t checksum; - unsigned int c; - uint32_t base = 0; - unsigned int last_address = 0x0; - - fd = open(filename, O_RDONLY); - if (fd < 0) - return PARSER_ERR_SYSTEM; - - /* read in the file */ - - while(read(fd, &mark, 1) != 0) { - if (mark == '\n' || mark == '\r') continue; - if (mark != ':') - return PARSER_ERR_INVALID_FILE; - - char buffer[9]; - unsigned int reclen, address, type; - uint8_t *record = NULL; - - /* get the reclen, address, and type */ - buffer[8] = 0; - if (read(fd, &buffer, 8) != 8) return PARSER_ERR_INVALID_FILE; - if (sscanf(buffer, "%2x%4x%2x", &reclen, &address, &type) != 3) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - /* setup the checksum */ - checksum = - reclen + - ((address & 0xFF00) >> 8) + - ((address & 0x00FF) >> 0) + - type; - - switch(type) { - /* data record */ - case 0: - c = address - last_address; - st->data = realloc(st->data, st->data_len + c + reclen); - - /* if there is a gap, set it to 0xff and increment the length */ - if (c > 0) { - memset(&st->data[st->data_len], 0xff, c); - st->data_len += c; - } - - last_address = address + reclen; - record = &st->data[st->data_len]; - st->data_len += reclen; - break; - - /* extended segment address record */ - case 2: - base = 0; - break; - - /* extended linear address record */ - case 4: - base = address; - break; - } - - buffer[2] = 0; - for(i = 0; i < reclen; ++i) { - if (read(fd, &buffer, 2) != 2 || sscanf(buffer, "%2x", &c) != 1) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - /* add the byte to the checksum */ - checksum += c; - - switch(type) { - case 0: - if (record != NULL) { - record[i] = c; - } else { - return PARSER_ERR_INVALID_FILE; - } - break; - - case 2: - case 4: - base = (base << 8) | c; - break; - } - } - - /* read, scan, and verify the checksum */ - if ( - read(fd, &buffer, 2 ) != 2 || - sscanf(buffer, "%2x", &c) != 1 || - (uint8_t)(checksum + c) != 0x00 - ) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - switch(type) { - /* EOF */ - case 1: - close(fd); - return PARSER_ERR_OK; - - /* address record */ - case 2: base = base << 4; - case 4: base = be_u32(base); - /* Reset last_address since our base changed */ - last_address = 0; - - if (st->base == 0) { - st->base = base; - break; - } - - /* we cant cope with files out of order */ - if (base < st->base) { - close(fd); - return PARSER_ERR_INVALID_FILE; - } - - /* if there is a gap, enlarge and fill with zeros */ - unsigned int len = base - st->base; - if (len > st->data_len) { - st->data = realloc(st->data, len); - memset(&st->data[st->data_len], 0, len - st->data_len); - st->data_len = len; - } - break; - } - } - - close(fd); - return PARSER_ERR_OK; - } -} - -parser_err_t hex_close(void *storage) { - hex_t *st = storage; - if (st) free(st->data); - free(st); - return PARSER_ERR_OK; -} - -unsigned int hex_size(void *storage) { - hex_t *st = storage; - return st->data_len; -} - -parser_err_t hex_read(void *storage, void *data, unsigned int *len) { - hex_t *st = storage; - unsigned int left = st->data_len - st->offset; - unsigned int get = left > *len ? *len : left; - - memcpy(data, &st->data[st->offset], get); - st->offset += get; - - *len = get; - return PARSER_ERR_OK; -} - -parser_err_t hex_write(void *storage, void *data, unsigned int len) { - return PARSER_ERR_RDONLY; -} - -parser_t PARSER_HEX = { - "Intel HEX", - hex_init, - hex_open, - hex_close, - hex_size, - hex_read, - hex_write -}; - diff --git a/win/src/stm32flash_serial/src/parsers/hex.h b/win/src/stm32flash_serial/src/parsers/hex.h deleted file mode 100644 index 02413c9c9..000000000 --- a/win/src/stm32flash_serial/src/parsers/hex.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _PARSER_HEX_H -#define _PARSER_HEX_H - -#include "parser.h" - -extern parser_t PARSER_HEX; -#endif diff --git a/win/src/stm32flash_serial/src/parsers/parser.h b/win/src/stm32flash_serial/src/parsers/parser.h deleted file mode 100644 index c2fae3cf8..000000000 --- a/win/src/stm32flash_serial/src/parsers/parser.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _H_PARSER -#define _H_PARSER - -enum parser_err { - PARSER_ERR_OK, - PARSER_ERR_SYSTEM, - PARSER_ERR_INVALID_FILE, - PARSER_ERR_WRONLY, - PARSER_ERR_RDONLY -}; -typedef enum parser_err parser_err_t; - -struct parser { - const char *name; - void* (*init )(); /* initialise the parser */ - parser_err_t (*open )(void *storage, const char *filename, const char write); /* open the file for read|write */ - parser_err_t (*close)(void *storage); /* close and free the parser */ - unsigned int (*size )(void *storage); /* get the total data size */ - parser_err_t (*read )(void *storage, void *data, unsigned int *len); /* read a block of data */ - parser_err_t (*write)(void *storage, void *data, unsigned int len); /* write a block of data */ -}; -typedef struct parser parser_t; - -static inline const char* parser_errstr(parser_err_t err) { - switch(err) { - case PARSER_ERR_OK : return "OK"; - case PARSER_ERR_SYSTEM : return "System Error"; - case PARSER_ERR_INVALID_FILE: return "Invalid File"; - case PARSER_ERR_WRONLY : return "Parser can only write"; - case PARSER_ERR_RDONLY : return "Parser can only read"; - default: - return "Unknown Error"; - } -} - -#endif diff --git a/win/src/stm32flash_serial/src/port.c b/win/src/stm32flash_serial/src/port.c deleted file mode 100644 index 08e58cc34..000000000 --- a/win/src/stm32flash_serial/src/port.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include - -#include "serial.h" -#include "port.h" - - -extern struct port_interface port_serial; -extern struct port_interface port_i2c; - -static struct port_interface *ports[] = { - &port_serial, - &port_i2c, - NULL, -}; - - -port_err_t port_open(struct port_options *ops, struct port_interface **outport) -{ - int ret; - static struct port_interface **port; - - for (port = ports; *port; port++) { - ret = (*port)->open(*port, ops); - if (ret == PORT_ERR_NODEV) - continue; - if (ret == PORT_ERR_OK) - break; - fprintf(stderr, "Error probing interface \"%s\"\n", - (*port)->name); - } - if (*port == NULL) { - fprintf(stderr, "Cannot handle device \"%s\"\n", - ops->device); - return PORT_ERR_UNKNOWN; - } - - *outport = *port; - return PORT_ERR_OK; -} diff --git a/win/src/stm32flash_serial/src/port.h b/win/src/stm32flash_serial/src/port.h deleted file mode 100644 index 290f03496..000000000 --- a/win/src/stm32flash_serial/src/port.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2014 Antonio Borneo - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _H_PORT -#define _H_PORT - -typedef enum { - PORT_ERR_OK = 0, - PORT_ERR_NODEV, /* No such device */ - PORT_ERR_TIMEDOUT, /* Operation timed out */ - PORT_ERR_UNKNOWN, -} port_err_t; - -/* flags */ -#define PORT_BYTE (1 << 0) /* byte (not frame) oriented */ -#define PORT_GVR_ETX (1 << 1) /* cmd GVR returns protection status */ -#define PORT_CMD_INIT (1 << 2) /* use INIT cmd to autodetect speed */ -#define PORT_RETRY (1 << 3) /* allowed read() retry after timeout */ -#define PORT_STRETCH_W (1 << 4) /* warning for no-stretching commands */ - -/* all options and flags used to open and configure an interface */ -struct port_options { - const char *device; - serial_baud_t baudRate; - const char *serial_mode; - int bus_addr; - int rx_frame_max; - int tx_frame_max; -}; - -/* - * Specify the length of reply for command GET - * This is helpful for frame-oriented protocols, e.g. i2c, to avoid time - * consuming try-fail-timeout-retry operation. - * On byte-oriented protocols, i.e. UART, this information would be skipped - * after read the first byte, so not needed. - */ -struct varlen_cmd { - uint8_t version; - uint8_t length; -}; - -struct port_interface { - const char *name; - unsigned flags; - port_err_t (*open)(struct port_interface *port, struct port_options *ops); - port_err_t (*close)(struct port_interface *port); - port_err_t (*read)(struct port_interface *port, void *buf, size_t nbyte); - port_err_t (*write)(struct port_interface *port, void *buf, size_t nbyte); - port_err_t (*gpio)(struct port_interface *port, serial_gpio_t n, int level); - const char *(*get_cfg_str)(struct port_interface *port); - struct varlen_cmd *cmd_get_reply; - void *private; -}; - -port_err_t port_open(struct port_options *ops, struct port_interface **outport); - -#endif diff --git a/win/src/stm32flash_serial/src/protocol.txt b/win/src/stm32flash_serial/src/protocol.txt deleted file mode 100644 index 039109908..000000000 --- a/win/src/stm32flash_serial/src/protocol.txt +++ /dev/null @@ -1,19 +0,0 @@ -The communication protocol used by ST bootloader is documented in following ST -application notes, depending on communication port. - -In current version of stm32flash are supported only UART and I2C ports. - -* AN3154: CAN protocol used in the STM32 bootloader - http://www.st.com/web/en/resource/technical/document/application_note/CD00264321.pdf - -* AN3155: USART protocol used in the STM32(TM) bootloader - http://www.st.com/web/en/resource/technical/document/application_note/CD00264342.pdf - -* AN4221: I2C protocol used in the STM32 bootloader - http://www.st.com/web/en/resource/technical/document/application_note/DM00072315.pdf - -* AN4286: SPI protocol used in the STM32 bootloader - http://www.st.com/web/en/resource/technical/document/application_note/DM00081379.pdf - -Boot mode selection for STM32 is documented in ST application note AN2606, available in ST website: - http://www.st.com/web/en/resource/technical/document/application_note/CD00167594.pdf diff --git a/win/src/stm32flash_serial/src/serial.h b/win/src/stm32flash_serial/src/serial.h deleted file mode 100644 index 227ba163b..000000000 --- a/win/src/stm32flash_serial/src/serial.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _SERIAL_H -#define _SERIAL_H - -typedef struct serial serial_t; - -typedef enum { - SERIAL_PARITY_NONE, - SERIAL_PARITY_EVEN, - SERIAL_PARITY_ODD, - - SERIAL_PARITY_INVALID -} serial_parity_t; - -typedef enum { - SERIAL_BITS_5, - SERIAL_BITS_6, - SERIAL_BITS_7, - SERIAL_BITS_8, - - SERIAL_BITS_INVALID -} serial_bits_t; - -typedef enum { - SERIAL_BAUD_1200, - SERIAL_BAUD_1800, - SERIAL_BAUD_2400, - SERIAL_BAUD_4800, - SERIAL_BAUD_9600, - SERIAL_BAUD_19200, - SERIAL_BAUD_38400, - SERIAL_BAUD_57600, - SERIAL_BAUD_115200, - SERIAL_BAUD_128000, - SERIAL_BAUD_230400, - SERIAL_BAUD_256000, - SERIAL_BAUD_460800, - SERIAL_BAUD_500000, - SERIAL_BAUD_576000, - SERIAL_BAUD_921600, - SERIAL_BAUD_1000000, - SERIAL_BAUD_1500000, - SERIAL_BAUD_2000000, - - SERIAL_BAUD_INVALID -} serial_baud_t; - -typedef enum { - SERIAL_STOPBIT_1, - SERIAL_STOPBIT_2, - - SERIAL_STOPBIT_INVALID -} serial_stopbit_t; - -typedef enum { - GPIO_RTS = 1, - GPIO_DTR, - GPIO_BRK, -} serial_gpio_t; - -/* common helper functions */ -serial_baud_t serial_get_baud(const unsigned int baud); -unsigned int serial_get_baud_int(const serial_baud_t baud); -serial_bits_t serial_get_bits(const char *mode); -unsigned int serial_get_bits_int(const serial_bits_t bits); -serial_parity_t serial_get_parity(const char *mode); -char serial_get_parity_str(const serial_parity_t parity); -serial_stopbit_t serial_get_stopbit(const char *mode); -unsigned int serial_get_stopbit_int(const serial_stopbit_t stopbit); - -#endif diff --git a/win/src/stm32flash_serial/src/serial_common.c b/win/src/stm32flash_serial/src/serial_common.c deleted file mode 100644 index 43e48e1ac..000000000 --- a/win/src/stm32flash_serial/src/serial_common.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include "serial.h" - -serial_baud_t serial_get_baud(const unsigned int baud) { - switch(baud) { - case 1200: return SERIAL_BAUD_1200 ; - case 1800: return SERIAL_BAUD_1800 ; - case 2400: return SERIAL_BAUD_2400 ; - case 4800: return SERIAL_BAUD_4800 ; - case 9600: return SERIAL_BAUD_9600 ; - case 19200: return SERIAL_BAUD_19200 ; - case 38400: return SERIAL_BAUD_38400 ; - case 57600: return SERIAL_BAUD_57600 ; - case 115200: return SERIAL_BAUD_115200; - case 128000: return SERIAL_BAUD_128000; - case 230400: return SERIAL_BAUD_230400; - case 256000: return SERIAL_BAUD_256000; - case 460800: return SERIAL_BAUD_460800; - case 500000: return SERIAL_BAUD_500000; - case 576000: return SERIAL_BAUD_576000; - case 921600: return SERIAL_BAUD_921600; - case 1000000: return SERIAL_BAUD_1000000; - case 1500000: return SERIAL_BAUD_1500000; - case 2000000: return SERIAL_BAUD_2000000; - - default: - return SERIAL_BAUD_INVALID; - } -} - -unsigned int serial_get_baud_int(const serial_baud_t baud) { - switch(baud) { - case SERIAL_BAUD_1200 : return 1200 ; - case SERIAL_BAUD_1800 : return 1800 ; - case SERIAL_BAUD_2400 : return 2400 ; - case SERIAL_BAUD_4800 : return 4800 ; - case SERIAL_BAUD_9600 : return 9600 ; - case SERIAL_BAUD_19200 : return 19200 ; - case SERIAL_BAUD_38400 : return 38400 ; - case SERIAL_BAUD_57600 : return 57600 ; - case SERIAL_BAUD_115200: return 115200; - case SERIAL_BAUD_128000: return 128000; - case SERIAL_BAUD_230400: return 230400; - case SERIAL_BAUD_256000: return 256000; - case SERIAL_BAUD_460800: return 460800; - case SERIAL_BAUD_500000: return 500000; - case SERIAL_BAUD_576000: return 576000; - case SERIAL_BAUD_921600: return 921600; - case SERIAL_BAUD_1000000: return 1000000; - case SERIAL_BAUD_1500000: return 1500000; - case SERIAL_BAUD_2000000: return 2000000; - - case SERIAL_BAUD_INVALID: - default: - return 0; - } -} - -serial_bits_t serial_get_bits(const char *mode) { - if (!mode) - return SERIAL_BITS_INVALID; - switch(mode[0]) { - case '5': return SERIAL_BITS_5; - case '6': return SERIAL_BITS_6; - case '7': return SERIAL_BITS_7; - case '8': return SERIAL_BITS_8; - - default: - return SERIAL_BITS_INVALID; - } -} - -unsigned int serial_get_bits_int(const serial_bits_t bits) { - switch(bits) { - case SERIAL_BITS_5: return 5; - case SERIAL_BITS_6: return 6; - case SERIAL_BITS_7: return 7; - case SERIAL_BITS_8: return 8; - - default: - return 0; - } -} - -serial_parity_t serial_get_parity(const char *mode) { - if (!mode || !mode[0]) - return SERIAL_PARITY_INVALID; - switch(mode[1]) { - case 'N': - case 'n': - return SERIAL_PARITY_NONE; - case 'E': - case 'e': - return SERIAL_PARITY_EVEN; - case 'O': - case 'o': - return SERIAL_PARITY_ODD; - - default: - return SERIAL_PARITY_INVALID; - } -} - -char serial_get_parity_str(const serial_parity_t parity) { - switch(parity) { - case SERIAL_PARITY_NONE: return 'N'; - case SERIAL_PARITY_EVEN: return 'E'; - case SERIAL_PARITY_ODD : return 'O'; - - default: - return ' '; - } -} - -serial_stopbit_t serial_get_stopbit(const char *mode) { - if (!mode || !mode[0] || !mode[1]) - return SERIAL_STOPBIT_INVALID; - switch(mode[2]) { - case '1': return SERIAL_STOPBIT_1; - case '2': return SERIAL_STOPBIT_2; - - default: - return SERIAL_STOPBIT_INVALID; - } -} - -unsigned int serial_get_stopbit_int(const serial_stopbit_t stopbit) { - switch(stopbit) { - case SERIAL_STOPBIT_1: return 1; - case SERIAL_STOPBIT_2: return 2; - - default: - return 0; - } -} - diff --git a/win/src/stm32flash_serial/src/serial_platform.c b/win/src/stm32flash_serial/src/serial_platform.c deleted file mode 100644 index 98e256921..000000000 --- a/win/src/stm32flash_serial/src/serial_platform.c +++ /dev/null @@ -1,5 +0,0 @@ -#if defined(__WIN32__) || defined(__CYGWIN__) -# include "serial_w32.c" -#else -# include "serial_posix.c" -#endif diff --git a/win/src/stm32flash_serial/src/serial_posix.c b/win/src/stm32flash_serial/src/serial_posix.c deleted file mode 100644 index 284b35b20..000000000 --- a/win/src/stm32flash_serial/src/serial_posix.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "serial.h" -#include "port.h" - -struct serial { - int fd; - struct termios oldtio; - struct termios newtio; - char setup_str[11]; -}; - -static serial_t *serial_open(const char *device) -{ - serial_t *h = calloc(sizeof(serial_t), 1); - - h->fd = open(device, O_RDWR | O_NOCTTY | O_NDELAY); - if (h->fd < 0) { - free(h); - return NULL; - } - fcntl(h->fd, F_SETFL, 0); - - tcgetattr(h->fd, &h->oldtio); - tcgetattr(h->fd, &h->newtio); - - return h; -} - -static void serial_flush(const serial_t *h) -{ - tcflush(h->fd, TCIFLUSH); -} - -static void serial_close(serial_t *h) -{ - serial_flush(h); - tcsetattr(h->fd, TCSANOW, &h->oldtio); - close(h->fd); - free(h); -} - -static port_err_t serial_setup(serial_t *h, const serial_baud_t baud, - const serial_bits_t bits, - const serial_parity_t parity, - const serial_stopbit_t stopbit) -{ - speed_t port_baud; - tcflag_t port_bits; - tcflag_t port_parity; - tcflag_t port_stop; - struct termios settings; - - switch (baud) { - case SERIAL_BAUD_1200: port_baud = B1200; break; - case SERIAL_BAUD_1800: port_baud = B1800; break; - case SERIAL_BAUD_2400: port_baud = B2400; break; - case SERIAL_BAUD_4800: port_baud = B4800; break; - case SERIAL_BAUD_9600: port_baud = B9600; break; - case SERIAL_BAUD_19200: port_baud = B19200; break; - case SERIAL_BAUD_38400: port_baud = B38400; break; - case SERIAL_BAUD_57600: port_baud = B57600; break; - case SERIAL_BAUD_115200: port_baud = B115200; break; - case SERIAL_BAUD_230400: port_baud = B230400; break; -#ifdef B460800 - case SERIAL_BAUD_460800: port_baud = B460800; break; -#endif /* B460800 */ -#ifdef B921600 - case SERIAL_BAUD_921600: port_baud = B921600; break; -#endif /* B921600 */ -#ifdef B500000 - case SERIAL_BAUD_500000: port_baud = B500000; break; -#endif /* B500000 */ -#ifdef B576000 - case SERIAL_BAUD_576000: port_baud = B576000; break; -#endif /* B576000 */ -#ifdef B1000000 - case SERIAL_BAUD_1000000: port_baud = B1000000; break; -#endif /* B1000000 */ -#ifdef B1500000 - case SERIAL_BAUD_1500000: port_baud = B1500000; break; -#endif /* B1500000 */ -#ifdef B2000000 - case SERIAL_BAUD_2000000: port_baud = B2000000; break; -#endif /* B2000000 */ - - case SERIAL_BAUD_INVALID: - default: - return PORT_ERR_UNKNOWN; - } - - switch (bits) { - case SERIAL_BITS_5: port_bits = CS5; break; - case SERIAL_BITS_6: port_bits = CS6; break; - case SERIAL_BITS_7: port_bits = CS7; break; - case SERIAL_BITS_8: port_bits = CS8; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (parity) { - case SERIAL_PARITY_NONE: port_parity = 0; break; - case SERIAL_PARITY_EVEN: port_parity = PARENB; break; - case SERIAL_PARITY_ODD: port_parity = PARENB | PARODD; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (stopbit) { - case SERIAL_STOPBIT_1: port_stop = 0; break; - case SERIAL_STOPBIT_2: port_stop = CSTOPB; break; - - default: - return PORT_ERR_UNKNOWN; - } - - /* reset the settings */ -#ifndef __sun /* Used by GNU and BSD. Ignore __SVR4 in test. */ - cfmakeraw(&h->newtio); -#else /* __sun */ - h->newtio.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR - | IGNCR | ICRNL | IXON); - if (port_parity) - h->newtio.c_iflag |= INPCK; - - h->newtio.c_oflag &= ~OPOST; - h->newtio.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - h->newtio.c_cflag &= ~(CSIZE | PARENB); - h->newtio.c_cflag |= CS8; -#endif /* __sun */ -#ifdef __QNXNTO__ - h->newtio.c_cflag &= ~(CSIZE | IHFLOW | OHFLOW); -#else - h->newtio.c_cflag &= ~(CSIZE | CRTSCTS); -#endif - h->newtio.c_cflag &= ~(CSIZE | CRTSCTS); - h->newtio.c_iflag &= ~(IXON | IXOFF | IXANY | IGNPAR); - h->newtio.c_lflag &= ~(ECHOK | ECHOCTL | ECHOKE); - h->newtio.c_oflag &= ~(OPOST | ONLCR); - - /* setup the new settings */ - cfsetispeed(&h->newtio, port_baud); - cfsetospeed(&h->newtio, port_baud); - h->newtio.c_cflag |= - port_parity | - port_bits | - port_stop | - CLOCAL | - CREAD; - - h->newtio.c_cc[VMIN] = 0; - h->newtio.c_cc[VTIME] = 5; /* in units of 0.1 s */ - - /* set the settings */ - serial_flush(h); - if (tcsetattr(h->fd, TCSANOW, &h->newtio) != 0) - return PORT_ERR_UNKNOWN; - -/* this check fails on CDC-ACM devices, bits 16 and 17 of cflag differ! - * it has been disabled below for now -jcw, 2015-11-09 - if (settings.c_cflag != h->newtio.c_cflag) - fprintf(stderr, "c_cflag mismatch %lx\n", - settings.c_cflag ^ h->newtio.c_cflag); - */ - - /* confirm they were set */ - tcgetattr(h->fd, &settings); - if (settings.c_iflag != h->newtio.c_iflag || - settings.c_oflag != h->newtio.c_oflag || - //settings.c_cflag != h->newtio.c_cflag || - settings.c_lflag != h->newtio.c_lflag) - return PORT_ERR_UNKNOWN; - - snprintf(h->setup_str, sizeof(h->setup_str), "%u %d%c%d", - serial_get_baud_int(baud), - serial_get_bits_int(bits), - serial_get_parity_str(parity), - serial_get_stopbit_int(stopbit)); - return PORT_ERR_OK; -} - -/* - * Roger clark. - * This function is no longer used. But has just been commented out in case it needs - * to be reinstated in the future - -static int startswith(const char *haystack, const char *needle) { - return strncmp(haystack, needle, strlen(needle)) == 0; -} -*/ - -static int is_tty(const char *path) { - char resolved[PATH_MAX]; - - if(!realpath(path, resolved)) return 0; - - - /* - * Roger Clark - * Commented out this check, because on OSX some devices are /dev/cu - * and some users use symbolic links to devices, hence the name may not even start - * with /dev - - if(startswith(resolved, "/dev/tty")) return 1; - - return 0; - */ - - return 1; -} - -static port_err_t serial_posix_open(struct port_interface *port, - struct port_options *ops) -{ - serial_t *h; - - /* 1. check device name match */ - if (!is_tty(ops->device)) - return PORT_ERR_NODEV; - - /* 2. check options */ - if (ops->baudRate == SERIAL_BAUD_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_bits(ops->serial_mode) == SERIAL_BITS_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_parity(ops->serial_mode) == SERIAL_PARITY_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_stopbit(ops->serial_mode) == SERIAL_STOPBIT_INVALID) - return PORT_ERR_UNKNOWN; - - /* 3. open it */ - h = serial_open(ops->device); - if (h == NULL) - return PORT_ERR_UNKNOWN; - - /* 4. set options */ - if (serial_setup(h, ops->baudRate, - serial_get_bits(ops->serial_mode), - serial_get_parity(ops->serial_mode), - serial_get_stopbit(ops->serial_mode) - ) != PORT_ERR_OK) { - serial_close(h); - return PORT_ERR_UNKNOWN; - } - - port->private = h; - return PORT_ERR_OK; -} - -static port_err_t serial_posix_close(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - serial_close(h); - port->private = NULL; - return PORT_ERR_OK; -} - -static port_err_t serial_posix_read(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - ssize_t r; - uint8_t *pos = (uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - r = read(h->fd, pos, nbyte); - if (r == 0) - return PORT_ERR_TIMEDOUT; - if (r < 0) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_posix_write(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - ssize_t r; - const uint8_t *pos = (const uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - r = write(h->fd, pos, nbyte); - if (r < 1) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_posix_gpio(struct port_interface *port, - serial_gpio_t n, int level) -{ - serial_t *h; - int bit, lines; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - switch (n) { - case GPIO_RTS: - bit = TIOCM_RTS; - break; - - case GPIO_DTR: - bit = TIOCM_DTR; - break; - - case GPIO_BRK: - if (level == 0) - return PORT_ERR_OK; - if (tcsendbreak(h->fd, 1)) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; - - default: - return PORT_ERR_UNKNOWN; - } - - /* handle RTS/DTR */ - if (ioctl(h->fd, TIOCMGET, &lines)) - return PORT_ERR_UNKNOWN; - lines = level ? lines | bit : lines & ~bit; - if (ioctl(h->fd, TIOCMSET, &lines)) - return PORT_ERR_UNKNOWN; - - return PORT_ERR_OK; -} - -static const char *serial_posix_get_cfg_str(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - return h ? h->setup_str : "INVALID"; -} - -struct port_interface port_serial = { - .name = "serial_posix", - .flags = PORT_BYTE | PORT_GVR_ETX | PORT_CMD_INIT | PORT_RETRY, - .open = serial_posix_open, - .close = serial_posix_close, - .read = serial_posix_read, - .write = serial_posix_write, - .gpio = serial_posix_gpio, - .get_cfg_str = serial_posix_get_cfg_str, -}; diff --git a/win/src/stm32flash_serial/src/serial_w32.c b/win/src/stm32flash_serial/src/serial_w32.c deleted file mode 100644 index 56772c0a0..000000000 --- a/win/src/stm32flash_serial/src/serial_w32.c +++ /dev/null @@ -1,341 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - Copyright (C) 2010 Gareth McMullin - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "serial.h" -#include "port.h" - -struct serial { - HANDLE fd; - DCB oldtio; - DCB newtio; - char setup_str[11]; -}; - -static serial_t *serial_open(const char *device) -{ - serial_t *h = calloc(sizeof(serial_t), 1); - char *devName; - - /* timeout in ms */ - COMMTIMEOUTS timeouts = {MAXDWORD, MAXDWORD, 500, 0, 0}; - - /* Fix the device name if required */ - if (strlen(device) > 4 && device[0] != '\\') { - devName = calloc(1, strlen(device) + 5); - sprintf(devName, "\\\\.\\%s", device); - } else { - devName = (char *)device; - } - - /* Create file handle for port */ - h->fd = CreateFile(devName, GENERIC_READ | GENERIC_WRITE, - 0, /* Exclusive access */ - NULL, /* No security */ - OPEN_EXISTING, - 0, /* No overlap */ - NULL); - - if (devName != device) - free(devName); - - if (h->fd == INVALID_HANDLE_VALUE) { - if (GetLastError() == ERROR_FILE_NOT_FOUND) - fprintf(stderr, "File not found: %s\n", device); - return NULL; - } - - SetupComm(h->fd, 4096, 4096); /* Set input and output buffer size */ - - SetCommTimeouts(h->fd, &timeouts); - - SetCommMask(h->fd, EV_ERR); /* Notify us of error events */ - - GetCommState(h->fd, &h->oldtio); /* Retrieve port parameters */ - GetCommState(h->fd, &h->newtio); /* Retrieve port parameters */ - - /* PurgeComm(h->fd, PURGE_RXABORT | PURGE_TXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); */ - - return h; -} - -static void serial_flush(const serial_t *h) -{ - /* We shouldn't need to flush in non-overlapping (blocking) mode */ - /* tcflush(h->fd, TCIFLUSH); */ -} - -static void serial_close(serial_t *h) -{ - serial_flush(h); - SetCommState(h->fd, &h->oldtio); - CloseHandle(h->fd); - free(h); -} - -static port_err_t serial_setup(serial_t *h, - const serial_baud_t baud, - const serial_bits_t bits, - const serial_parity_t parity, - const serial_stopbit_t stopbit) -{ - switch (baud) { - case SERIAL_BAUD_1200: h->newtio.BaudRate = CBR_1200; break; - /* case SERIAL_BAUD_1800: h->newtio.BaudRate = CBR_1800; break; */ - case SERIAL_BAUD_2400: h->newtio.BaudRate = CBR_2400; break; - case SERIAL_BAUD_4800: h->newtio.BaudRate = CBR_4800; break; - case SERIAL_BAUD_9600: h->newtio.BaudRate = CBR_9600; break; - case SERIAL_BAUD_19200: h->newtio.BaudRate = CBR_19200; break; - case SERIAL_BAUD_38400: h->newtio.BaudRate = CBR_38400; break; - case SERIAL_BAUD_57600: h->newtio.BaudRate = CBR_57600; break; - case SERIAL_BAUD_115200: h->newtio.BaudRate = CBR_115200; break; - case SERIAL_BAUD_128000: h->newtio.BaudRate = CBR_128000; break; - case SERIAL_BAUD_256000: h->newtio.BaudRate = CBR_256000; break; - /* These are not defined in WinBase.h and might work or not */ - case SERIAL_BAUD_230400: h->newtio.BaudRate = 230400; break; - case SERIAL_BAUD_460800: h->newtio.BaudRate = 460800; break; - case SERIAL_BAUD_500000: h->newtio.BaudRate = 500000; break; - case SERIAL_BAUD_576000: h->newtio.BaudRate = 576000; break; - case SERIAL_BAUD_921600: h->newtio.BaudRate = 921600; break; - case SERIAL_BAUD_1000000: h->newtio.BaudRate = 1000000; break; - case SERIAL_BAUD_1500000: h->newtio.BaudRate = 1500000; break; - case SERIAL_BAUD_2000000: h->newtio.BaudRate = 2000000; break; - case SERIAL_BAUD_INVALID: - - default: - return PORT_ERR_UNKNOWN; - } - - switch (bits) { - case SERIAL_BITS_5: h->newtio.ByteSize = 5; break; - case SERIAL_BITS_6: h->newtio.ByteSize = 6; break; - case SERIAL_BITS_7: h->newtio.ByteSize = 7; break; - case SERIAL_BITS_8: h->newtio.ByteSize = 8; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (parity) { - case SERIAL_PARITY_NONE: h->newtio.Parity = NOPARITY; break; - case SERIAL_PARITY_EVEN: h->newtio.Parity = EVENPARITY; break; - case SERIAL_PARITY_ODD: h->newtio.Parity = ODDPARITY; break; - - default: - return PORT_ERR_UNKNOWN; - } - - switch (stopbit) { - case SERIAL_STOPBIT_1: h->newtio.StopBits = ONESTOPBIT; break; - case SERIAL_STOPBIT_2: h->newtio.StopBits = TWOSTOPBITS; break; - - default: - return PORT_ERR_UNKNOWN; - } - - /* reset the settings */ - h->newtio.fOutxCtsFlow = FALSE; - h->newtio.fOutxDsrFlow = FALSE; - h->newtio.fOutX = FALSE; - h->newtio.fInX = FALSE; - h->newtio.fNull = 0; - h->newtio.fAbortOnError = 0; - - /* set the settings */ - serial_flush(h); - if (!SetCommState(h->fd, &h->newtio)) - return PORT_ERR_UNKNOWN; - - snprintf(h->setup_str, sizeof(h->setup_str), "%u %d%c%d", - serial_get_baud_int(baud), - serial_get_bits_int(bits), - serial_get_parity_str(parity), - serial_get_stopbit_int(stopbit) - ); - return PORT_ERR_OK; -} - -static port_err_t serial_w32_open(struct port_interface *port, - struct port_options *ops) -{ - serial_t *h; - - /* 1. check device name match */ - if (!((strlen(ops->device) == 4 || strlen(ops->device) == 5) - && !strncmp(ops->device, "COM", 3) && isdigit(ops->device[3])) - && !(!strncmp(ops->device, "\\\\.\\COM", strlen("\\\\.\\COM")) - && isdigit(ops->device[strlen("\\\\.\\COM")]))) - return PORT_ERR_NODEV; - - /* 2. check options */ - if (ops->baudRate == SERIAL_BAUD_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_bits(ops->serial_mode) == SERIAL_BITS_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_parity(ops->serial_mode) == SERIAL_PARITY_INVALID) - return PORT_ERR_UNKNOWN; - if (serial_get_stopbit(ops->serial_mode) == SERIAL_STOPBIT_INVALID) - return PORT_ERR_UNKNOWN; - - /* 3. open it */ - h = serial_open(ops->device); - if (h == NULL) - return PORT_ERR_UNKNOWN; - - /* 4. set options */ - if (serial_setup(h, ops->baudRate, - serial_get_bits(ops->serial_mode), - serial_get_parity(ops->serial_mode), - serial_get_stopbit(ops->serial_mode) - ) != PORT_ERR_OK) { - serial_close(h); - return PORT_ERR_UNKNOWN; - } - - port->private = h; - return PORT_ERR_OK; -} - -static port_err_t serial_w32_close(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - serial_close(h); - port->private = NULL; - return PORT_ERR_OK; -} - -static port_err_t serial_w32_read(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - DWORD r; - uint8_t *pos = (uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - ReadFile(h->fd, pos, nbyte, &r, NULL); - if (r == 0) - return PORT_ERR_TIMEDOUT; - if (r < 0) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_w32_write(struct port_interface *port, void *buf, - size_t nbyte) -{ - serial_t *h; - DWORD r; - uint8_t *pos = (uint8_t *)buf; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - while (nbyte) { - if (!WriteFile(h->fd, pos, nbyte, &r, NULL)) - return PORT_ERR_UNKNOWN; - if (r < 1) - return PORT_ERR_UNKNOWN; - - nbyte -= r; - pos += r; - } - return PORT_ERR_OK; -} - -static port_err_t serial_w32_gpio(struct port_interface *port, - serial_gpio_t n, int level) -{ - serial_t *h; - int bit; - - h = (serial_t *)port->private; - if (h == NULL) - return PORT_ERR_UNKNOWN; - - switch (n) { - case GPIO_RTS: - bit = level ? SETRTS : CLRRTS; - break; - - case GPIO_DTR: - bit = level ? SETDTR : CLRDTR; - break; - - case GPIO_BRK: - if (level == 0) - return PORT_ERR_OK; - if (EscapeCommFunction(h->fd, SETBREAK) == 0) - return PORT_ERR_UNKNOWN; - usleep(500000); - if (EscapeCommFunction(h->fd, CLRBREAK) == 0) - return PORT_ERR_UNKNOWN; - return PORT_ERR_OK; - - default: - return PORT_ERR_UNKNOWN; - } - - /* handle RTS/DTR */ - if (EscapeCommFunction(h->fd, bit) == 0) - return PORT_ERR_UNKNOWN; - - return PORT_ERR_OK; -} - -static const char *serial_w32_get_cfg_str(struct port_interface *port) -{ - serial_t *h; - - h = (serial_t *)port->private; - return h ? h->setup_str : "INVALID"; -} - -struct port_interface port_serial = { - .name = "serial_w32", - .flags = PORT_BYTE | PORT_GVR_ETX | PORT_CMD_INIT | PORT_RETRY, - .open = serial_w32_open, - .close = serial_w32_close, - .read = serial_w32_read, - .write = serial_w32_write, - .gpio = serial_w32_gpio, - .get_cfg_str = serial_w32_get_cfg_str, -}; diff --git a/win/src/stm32flash_serial/src/stm32.c b/win/src/stm32flash_serial/src/stm32.c deleted file mode 100644 index 74047d244..000000000 --- a/win/src/stm32flash_serial/src/stm32.c +++ /dev/null @@ -1,1048 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright 2010 Geoffrey McRae - Copyright 2012-2014 Tormod Volden - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include -#include -#include -#include -#include - -#include "stm32.h" -#include "port.h" -#include "utils.h" - -#define STM32_ACK 0x79 -#define STM32_NACK 0x1F -#define STM32_BUSY 0x76 - -#define STM32_CMD_INIT 0x7F -#define STM32_CMD_GET 0x00 /* get the version and command supported */ -#define STM32_CMD_GVR 0x01 /* get version and read protection status */ -#define STM32_CMD_GID 0x02 /* get ID */ -#define STM32_CMD_RM 0x11 /* read memory */ -#define STM32_CMD_GO 0x21 /* go */ -#define STM32_CMD_WM 0x31 /* write memory */ -#define STM32_CMD_WM_NS 0x32 /* no-stretch write memory */ -#define STM32_CMD_ER 0x43 /* erase */ -#define STM32_CMD_EE 0x44 /* extended erase */ -#define STM32_CMD_EE_NS 0x45 /* extended erase no-stretch */ -#define STM32_CMD_WP 0x63 /* write protect */ -#define STM32_CMD_WP_NS 0x64 /* write protect no-stretch */ -#define STM32_CMD_UW 0x73 /* write unprotect */ -#define STM32_CMD_UW_NS 0x74 /* write unprotect no-stretch */ -#define STM32_CMD_RP 0x82 /* readout protect */ -#define STM32_CMD_RP_NS 0x83 /* readout protect no-stretch */ -#define STM32_CMD_UR 0x92 /* readout unprotect */ -#define STM32_CMD_UR_NS 0x93 /* readout unprotect no-stretch */ -#define STM32_CMD_CRC 0xA1 /* compute CRC */ -#define STM32_CMD_ERR 0xFF /* not a valid command */ - -#define STM32_RESYNC_TIMEOUT 35 /* seconds */ -#define STM32_MASSERASE_TIMEOUT 35 /* seconds */ -#define STM32_SECTERASE_TIMEOUT 5 /* seconds */ -#define STM32_BLKWRITE_TIMEOUT 1 /* seconds */ -#define STM32_WUNPROT_TIMEOUT 1 /* seconds */ -#define STM32_WPROT_TIMEOUT 1 /* seconds */ -#define STM32_RPROT_TIMEOUT 1 /* seconds */ - -#define STM32_CMD_GET_LENGTH 17 /* bytes in the reply */ - -struct stm32_cmd { - uint8_t get; - uint8_t gvr; - uint8_t gid; - uint8_t rm; - uint8_t go; - uint8_t wm; - uint8_t er; /* this may be extended erase */ - uint8_t wp; - uint8_t uw; - uint8_t rp; - uint8_t ur; - uint8_t crc; -}; - -/* Reset code for ARMv7-M (Cortex-M3) and ARMv6-M (Cortex-M0) - * see ARMv7-M or ARMv6-M Architecture Reference Manual (table B3-8) - * or "The definitive guide to the ARM Cortex-M3", section 14.4. - */ -static const uint8_t stm_reset_code[] = { - 0x01, 0x49, // ldr r1, [pc, #4] ; () - 0x02, 0x4A, // ldr r2, [pc, #8] ; () - 0x0A, 0x60, // str r2, [r1, #0] - 0xfe, 0xe7, // endless: b endless - 0x0c, 0xed, 0x00, 0xe0, // .word 0xe000ed0c = NVIC AIRCR register address - 0x04, 0x00, 0xfa, 0x05 // .word 0x05fa0004 = VECTKEY | SYSRESETREQ -}; - -static const uint32_t stm_reset_code_length = sizeof(stm_reset_code); - -extern const stm32_dev_t devices[]; - -static void stm32_warn_stretching(const char *f) -{ - fprintf(stderr, "Attention !!!\n"); - fprintf(stderr, "\tThis %s error could be caused by your I2C\n", f); - fprintf(stderr, "\tcontroller not accepting \"clock stretching\"\n"); - fprintf(stderr, "\tas required by bootloader.\n"); - fprintf(stderr, "\tCheck \"I2C.txt\" in stm32flash source code.\n"); -} - -static stm32_err_t stm32_get_ack_timeout(const stm32_t *stm, time_t timeout) -{ - struct port_interface *port = stm->port; - uint8_t byte; - port_err_t p_err; - time_t t0, t1; - - if (!(port->flags & PORT_RETRY)) - timeout = 0; - - if (timeout) - time(&t0); - - do { - p_err = port->read(port, &byte, 1); - if (p_err == PORT_ERR_TIMEDOUT && timeout) { - time(&t1); - if (t1 < t0 + timeout) - continue; - } - - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to read ACK byte\n"); - return STM32_ERR_UNKNOWN; - } - - if (byte == STM32_ACK) - return STM32_ERR_OK; - if (byte == STM32_NACK) - return STM32_ERR_NACK; - if (byte != STM32_BUSY) { - fprintf(stderr, "Got byte 0x%02x instead of ACK\n", - byte); - return STM32_ERR_UNKNOWN; - } - } while (1); -} - -static stm32_err_t stm32_get_ack(const stm32_t *stm) -{ - return stm32_get_ack_timeout(stm, 0); -} - -static stm32_err_t stm32_send_command_timeout(const stm32_t *stm, - const uint8_t cmd, - time_t timeout) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - port_err_t p_err; - uint8_t buf[2]; - - buf[0] = cmd; - buf[1] = cmd ^ 0xFF; - p_err = port->write(port, buf, 2); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to send command\n"); - return STM32_ERR_UNKNOWN; - } - s_err = stm32_get_ack_timeout(stm, timeout); - if (s_err == STM32_ERR_OK) - return STM32_ERR_OK; - if (s_err == STM32_ERR_NACK) - fprintf(stderr, "Got NACK from device on command 0x%02x\n", cmd); - else - fprintf(stderr, "Unexpected reply from device on command 0x%02x\n", cmd); - return STM32_ERR_UNKNOWN; -} - -static stm32_err_t stm32_send_command(const stm32_t *stm, const uint8_t cmd) -{ - return stm32_send_command_timeout(stm, cmd, 0); -} - -/* if we have lost sync, send a wrong command and expect a NACK */ -static stm32_err_t stm32_resync(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - port_err_t p_err; - uint8_t buf[2], ack; - time_t t0, t1; - - time(&t0); - t1 = t0; - - buf[0] = STM32_CMD_ERR; - buf[1] = STM32_CMD_ERR ^ 0xFF; - while (t1 < t0 + STM32_RESYNC_TIMEOUT) { - p_err = port->write(port, buf, 2); - if (p_err != PORT_ERR_OK) { - usleep(500000); - time(&t1); - continue; - } - p_err = port->read(port, &ack, 1); - if (p_err != PORT_ERR_OK) { - time(&t1); - continue; - } - if (ack == STM32_NACK) - return STM32_ERR_OK; - time(&t1); - } - return STM32_ERR_UNKNOWN; -} - -/* - * some command receive reply frame with variable length, and length is - * embedded in reply frame itself. - * We can guess the length, but if we guess wrong the protocol gets out - * of sync. - * Use resync for frame oriented interfaces (e.g. I2C) and byte-by-byte - * read for byte oriented interfaces (e.g. UART). - * - * to run safely, data buffer should be allocated for 256+1 bytes - * - * len is value of the first byte in the frame. - */ -static stm32_err_t stm32_guess_len_cmd(const stm32_t *stm, uint8_t cmd, - uint8_t *data, unsigned int len) -{ - struct port_interface *port = stm->port; - port_err_t p_err; - - if (stm32_send_command(stm, cmd) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - if (port->flags & PORT_BYTE) { - /* interface is UART-like */ - p_err = port->read(port, data, 1); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - len = data[0]; - p_err = port->read(port, data + 1, len + 1); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - return STM32_ERR_OK; - } - - p_err = port->read(port, data, len + 2); - if (p_err == PORT_ERR_OK && len == data[0]) - return STM32_ERR_OK; - if (p_err != PORT_ERR_OK) { - /* restart with only one byte */ - if (stm32_resync(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - if (stm32_send_command(stm, cmd) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - p_err = port->read(port, data, 1); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - } - - fprintf(stderr, "Re sync (len = %d)\n", data[0]); - if (stm32_resync(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - len = data[0]; - if (stm32_send_command(stm, cmd) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - p_err = port->read(port, data, len + 2); - if (p_err != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - return STM32_ERR_OK; -} - -/* - * Some interface, e.g. UART, requires a specific init sequence to let STM32 - * autodetect the interface speed. - * The sequence is only required one time after reset. - * stm32flash has command line flag "-c" to prevent sending the init sequence - * in case it was already sent before. - * User can easily forget adding "-c". In this case the bootloader would - * interpret the init sequence as part of a command message, then waiting for - * the rest of the message blocking the interface. - * This function sends the init sequence and, in case of timeout, recovers - * the interface. - */ -static stm32_err_t stm32_send_init_seq(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - port_err_t p_err; - uint8_t byte, cmd = STM32_CMD_INIT; - - p_err = port->write(port, &cmd, 1); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to send init to device\n"); - return STM32_ERR_UNKNOWN; - } - p_err = port->read(port, &byte, 1); - if (p_err == PORT_ERR_OK && byte == STM32_ACK) - return STM32_ERR_OK; - if (p_err == PORT_ERR_OK && byte == STM32_NACK) { - /* We could get error later, but let's continue, for now. */ - fprintf(stderr, - "Warning: the interface was not closed properly.\n"); - return STM32_ERR_OK; - } - if (p_err != PORT_ERR_TIMEDOUT) { - fprintf(stderr, "Failed to init device.\n"); - return STM32_ERR_UNKNOWN; - } - - /* - * Check if previous STM32_CMD_INIT was taken as first byte - * of a command. Send a new byte, we should get back a NACK. - */ - p_err = port->write(port, &cmd, 1); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Failed to send init to device\n"); - return STM32_ERR_UNKNOWN; - } - p_err = port->read(port, &byte, 1); - if (p_err == PORT_ERR_OK && byte == STM32_NACK) - return STM32_ERR_OK; - fprintf(stderr, "Failed to init device.\n"); - return STM32_ERR_UNKNOWN; -} - -/* find newer command by higher code */ -#define newer(prev, a) (((prev) == STM32_CMD_ERR) \ - ? (a) \ - : (((prev) > (a)) ? (prev) : (a))) - -stm32_t *stm32_init(struct port_interface *port, const char init) -{ - uint8_t len, val, buf[257]; - stm32_t *stm; - int i, new_cmds; - - stm = calloc(sizeof(stm32_t), 1); - stm->cmd = malloc(sizeof(stm32_cmd_t)); - memset(stm->cmd, STM32_CMD_ERR, sizeof(stm32_cmd_t)); - stm->port = port; - - if ((port->flags & PORT_CMD_INIT) && init) - if (stm32_send_init_seq(stm) != STM32_ERR_OK) - return NULL; - - /* get the version and read protection status */ - if (stm32_send_command(stm, STM32_CMD_GVR) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - /* From AN, only UART bootloader returns 3 bytes */ - len = (port->flags & PORT_GVR_ETX) ? 3 : 1; - if (port->read(port, buf, len) != PORT_ERR_OK) - return NULL; - stm->version = buf[0]; - stm->option1 = (port->flags & PORT_GVR_ETX) ? buf[1] : 0; - stm->option2 = (port->flags & PORT_GVR_ETX) ? buf[2] : 0; - if (stm32_get_ack(stm) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - /* get the bootloader information */ - len = STM32_CMD_GET_LENGTH; - if (port->cmd_get_reply) - for (i = 0; port->cmd_get_reply[i].length; i++) - if (stm->version == port->cmd_get_reply[i].version) { - len = port->cmd_get_reply[i].length; - break; - } - if (stm32_guess_len_cmd(stm, STM32_CMD_GET, buf, len) != STM32_ERR_OK) - return NULL; - len = buf[0] + 1; - stm->bl_version = buf[1]; - new_cmds = 0; - for (i = 1; i < len; i++) { - val = buf[i + 1]; - switch (val) { - case STM32_CMD_GET: - stm->cmd->get = val; break; - case STM32_CMD_GVR: - stm->cmd->gvr = val; break; - case STM32_CMD_GID: - stm->cmd->gid = val; break; - case STM32_CMD_RM: - stm->cmd->rm = val; break; - case STM32_CMD_GO: - stm->cmd->go = val; break; - case STM32_CMD_WM: - case STM32_CMD_WM_NS: - stm->cmd->wm = newer(stm->cmd->wm, val); - break; - case STM32_CMD_ER: - case STM32_CMD_EE: - case STM32_CMD_EE_NS: - stm->cmd->er = newer(stm->cmd->er, val); - break; - case STM32_CMD_WP: - case STM32_CMD_WP_NS: - stm->cmd->wp = newer(stm->cmd->wp, val); - break; - case STM32_CMD_UW: - case STM32_CMD_UW_NS: - stm->cmd->uw = newer(stm->cmd->uw, val); - break; - case STM32_CMD_RP: - case STM32_CMD_RP_NS: - stm->cmd->rp = newer(stm->cmd->rp, val); - break; - case STM32_CMD_UR: - case STM32_CMD_UR_NS: - stm->cmd->ur = newer(stm->cmd->ur, val); - break; - case STM32_CMD_CRC: - stm->cmd->crc = newer(stm->cmd->crc, val); - break; - default: - if (new_cmds++ == 0) - fprintf(stderr, - "GET returns unknown commands (0x%2x", - val); - else - fprintf(stderr, ", 0x%2x", val); - } - } - if (new_cmds) - fprintf(stderr, ")\n"); - if (stm32_get_ack(stm) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - if (stm->cmd->get == STM32_CMD_ERR - || stm->cmd->gvr == STM32_CMD_ERR - || stm->cmd->gid == STM32_CMD_ERR) { - fprintf(stderr, "Error: bootloader did not returned correct information from GET command\n"); - return NULL; - } - - /* get the device ID */ - if (stm32_guess_len_cmd(stm, stm->cmd->gid, buf, 1) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - len = buf[0] + 1; - if (len < 2) { - stm32_close(stm); - fprintf(stderr, "Only %d bytes sent in the PID, unknown/unsupported device\n", len); - return NULL; - } - stm->pid = (buf[1] << 8) | buf[2]; - if (len > 2) { - fprintf(stderr, "This bootloader returns %d extra bytes in PID:", len); - for (i = 2; i <= len ; i++) - fprintf(stderr, " %02x", buf[i]); - fprintf(stderr, "\n"); - } - if (stm32_get_ack(stm) != STM32_ERR_OK) { - stm32_close(stm); - return NULL; - } - - stm->dev = devices; - while (stm->dev->id != 0x00 && stm->dev->id != stm->pid) - ++stm->dev; - - if (!stm->dev->id) { - fprintf(stderr, "Unknown/unsupported device (Device ID: 0x%03x)\n", stm->pid); - stm32_close(stm); - return NULL; - } - - return stm; -} - -void stm32_close(stm32_t *stm) -{ - if (stm) - free(stm->cmd); - free(stm); -} - -stm32_err_t stm32_read_memory(const stm32_t *stm, uint32_t address, - uint8_t data[], unsigned int len) -{ - struct port_interface *port = stm->port; - uint8_t buf[5]; - - if (!len) - return STM32_ERR_OK; - - if (len > 256) { - fprintf(stderr, "Error: READ length limit at 256 bytes\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->rm == STM32_CMD_ERR) { - fprintf(stderr, "Error: READ command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->rm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_send_command(stm, len - 1) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (port->read(port, data, len) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - return STM32_ERR_OK; -} - -stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address, - const uint8_t data[], unsigned int len) -{ - struct port_interface *port = stm->port; - uint8_t cs, buf[256 + 2]; - unsigned int i, aligned_len; - stm32_err_t s_err; - - if (!len) - return STM32_ERR_OK; - - if (len > 256) { - fprintf(stderr, "Error: READ length limit at 256 bytes\n"); - return STM32_ERR_UNKNOWN; - } - - /* must be 32bit aligned */ - if (address & 0x3 || len & 0x3) { - fprintf(stderr, "Error: WRITE address and length must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->wm == STM32_CMD_ERR) { - fprintf(stderr, "Error: WRITE command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - /* send the address and checksum */ - if (stm32_send_command(stm, stm->cmd->wm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - aligned_len = (len + 3) & ~3; - cs = aligned_len - 1; - buf[0] = aligned_len - 1; - for (i = 0; i < len; i++) { - cs ^= data[i]; - buf[i + 1] = data[i]; - } - /* padding data */ - for (i = len; i < aligned_len; i++) { - cs ^= 0xFF; - buf[i + 1] = 0xFF; - } - buf[aligned_len + 1] = cs; - if (port->write(port, buf, aligned_len + 2) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_BLKWRITE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->wm != STM32_CMD_WM_NS) - stm32_warn_stretching("write"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_wunprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->uw == STM32_CMD_ERR) { - fprintf(stderr, "Error: WRITE UNPROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->uw) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_WUNPROT_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to WRITE UNPROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->uw != STM32_CMD_UW_NS) - stm32_warn_stretching("WRITE UNPROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_wprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->wp == STM32_CMD_ERR) { - fprintf(stderr, "Error: WRITE PROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->wp) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_WPROT_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to WRITE PROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->wp != STM32_CMD_WP_NS) - stm32_warn_stretching("WRITE PROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_runprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->ur == STM32_CMD_ERR) { - fprintf(stderr, "Error: READOUT UNPROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->ur) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to READOUT UNPROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->ur != STM32_CMD_UR_NS) - stm32_warn_stretching("READOUT UNPROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_readprot_memory(const stm32_t *stm) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - - if (stm->cmd->rp == STM32_CMD_ERR) { - fprintf(stderr, "Error: READOUT PROTECT command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->rp) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - s_err = stm32_get_ack_timeout(stm, STM32_RPROT_TIMEOUT); - if (s_err == STM32_NACK) { - fprintf(stderr, "Error: Failed to READOUT PROTECT\n"); - return STM32_ERR_UNKNOWN; - } - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W - && stm->cmd->rp != STM32_CMD_RP_NS) - stm32_warn_stretching("READOUT PROTECT"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; -} - -stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, uint8_t pages) -{ - struct port_interface *port = stm->port; - stm32_err_t s_err; - port_err_t p_err; - - if (!pages) - return STM32_ERR_OK; - - if (stm->cmd->er == STM32_CMD_ERR) { - fprintf(stderr, "Error: ERASE command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->er) != STM32_ERR_OK) { - fprintf(stderr, "Can't initiate chip erase!\n"); - return STM32_ERR_UNKNOWN; - } - - /* The erase command reported by the bootloader is either 0x43, 0x44 or 0x45 */ - /* 0x44 is Extended Erase, a 2 byte based protocol and needs to be handled differently. */ - /* 0x45 is clock no-stretching version of Extended Erase for I2C port. */ - if (stm->cmd->er != STM32_CMD_ER) { - /* Not all chips using Extended Erase support mass erase */ - /* Currently known as not supporting mass erase is the Ultra Low Power STM32L15xx range */ - /* So if someone has not overridden the default, but uses one of these chips, take it out of */ - /* mass erase mode, so it will be done page by page. This maximum might not be correct either! */ - if (stm->pid == 0x416 && pages == 0xFF) - pages = 0xF8; /* works for the STM32L152RB with 128Kb flash */ - - if (pages == 0xFF) { - uint8_t buf[3]; - - /* 0xFFFF the magic number for mass erase */ - buf[0] = 0xFF; - buf[1] = 0xFF; - buf[2] = 0x00; /* checksum */ - if (port->write(port, buf, 3) != PORT_ERR_OK) { - fprintf(stderr, "Mass erase error.\n"); - return STM32_ERR_UNKNOWN; - } - s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Mass erase failed. Try specifying the number of pages to be erased.\n"); - if (port->flags & PORT_STRETCH_W - && stm->cmd->er != STM32_CMD_EE_NS) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; - } - - uint16_t pg_num; - uint8_t pg_byte; - uint8_t cs = 0; - uint8_t *buf; - int i = 0; - - buf = malloc(2 + 2 * pages + 1); - if (!buf) - return STM32_ERR_UNKNOWN; - - /* Number of pages to be erased - 1, two bytes, MSB first */ - pg_byte = (pages - 1) >> 8; - buf[i++] = pg_byte; - cs ^= pg_byte; - pg_byte = (pages - 1) & 0xFF; - buf[i++] = pg_byte; - cs ^= pg_byte; - - for (pg_num = spage; pg_num < spage + pages; pg_num++) { - pg_byte = pg_num >> 8; - cs ^= pg_byte; - buf[i++] = pg_byte; - pg_byte = pg_num & 0xFF; - cs ^= pg_byte; - buf[i++] = pg_byte; - } - buf[i++] = cs; - p_err = port->write(port, buf, i); - free(buf); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Page-by-page erase error.\n"); - return STM32_ERR_UNKNOWN; - } - - s_err = stm32_get_ack_timeout(stm, pages * STM32_SECTERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - fprintf(stderr, "Page-by-page erase failed. Check the maximum pages your device supports.\n"); - if (port->flags & PORT_STRETCH_W - && stm->cmd->er != STM32_CMD_EE_NS) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - - return STM32_ERR_OK; - } - - /* And now the regular erase (0x43) for all other chips */ - if (pages == 0xFF) { - s_err = stm32_send_command_timeout(stm, 0xFF, STM32_MASSERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; - } else { - uint8_t cs = 0; - uint8_t pg_num; - uint8_t *buf; - int i = 0; - - buf = malloc(1 + pages + 1); - if (!buf) - return STM32_ERR_UNKNOWN; - - buf[i++] = pages - 1; - cs ^= (pages-1); - for (pg_num = spage; pg_num < (pages + spage); pg_num++) { - buf[i++] = pg_num; - cs ^= pg_num; - } - buf[i++] = cs; - p_err = port->write(port, buf, i); - free(buf); - if (p_err != PORT_ERR_OK) { - fprintf(stderr, "Erase failed.\n"); - return STM32_ERR_UNKNOWN; - } - s_err = stm32_get_ack_timeout(stm, STM32_MASSERASE_TIMEOUT); - if (s_err != STM32_ERR_OK) { - if (port->flags & PORT_STRETCH_W) - stm32_warn_stretching("erase"); - return STM32_ERR_UNKNOWN; - } - return STM32_ERR_OK; - } -} - -static stm32_err_t stm32_run_raw_code(const stm32_t *stm, - uint32_t target_address, - const uint8_t *code, uint32_t code_size) -{ - uint32_t stack_le = le_u32(0x20002000); - uint32_t code_address_le = le_u32(target_address + 8); - uint32_t length = code_size + 8; - uint8_t *mem, *pos; - uint32_t address, w; - - /* Must be 32-bit aligned */ - if (target_address & 0x3) { - fprintf(stderr, "Error: code address must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - mem = malloc(length); - if (!mem) - return STM32_ERR_UNKNOWN; - - memcpy(mem, &stack_le, sizeof(uint32_t)); - memcpy(mem + 4, &code_address_le, sizeof(uint32_t)); - memcpy(mem + 8, code, code_size); - - pos = mem; - address = target_address; - while (length > 0) { - w = length > 256 ? 256 : length; - if (stm32_write_memory(stm, address, pos, w) != STM32_ERR_OK) { - free(mem); - return STM32_ERR_UNKNOWN; - } - - address += w; - pos += w; - length -= w; - } - - free(mem); - return stm32_go(stm, target_address); -} - -stm32_err_t stm32_go(const stm32_t *stm, uint32_t address) -{ - struct port_interface *port = stm->port; - uint8_t buf[5]; - - if (stm->cmd->go == STM32_CMD_ERR) { - fprintf(stderr, "Error: GO command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->go) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - return STM32_ERR_OK; -} - -stm32_err_t stm32_reset_device(const stm32_t *stm) -{ - uint32_t target_address = stm->dev->ram_start; - - return stm32_run_raw_code(stm, target_address, stm_reset_code, stm_reset_code_length); -} - -stm32_err_t stm32_crc_memory(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc) -{ - struct port_interface *port = stm->port; - uint8_t buf[5]; - - if (address & 0x3 || length & 0x3) { - fprintf(stderr, "Start and end addresses must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->crc == STM32_CMD_ERR) { - fprintf(stderr, "Error: CRC command not implemented in bootloader.\n"); - return STM32_ERR_NO_CMD; - } - - if (stm32_send_command(stm, stm->cmd->crc) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = address >> 24; - buf[1] = (address >> 16) & 0xFF; - buf[2] = (address >> 8) & 0xFF; - buf[3] = address & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - buf[0] = length >> 24; - buf[1] = (length >> 16) & 0xFF; - buf[2] = (length >> 8) & 0xFF; - buf[3] = length & 0xFF; - buf[4] = buf[0] ^ buf[1] ^ buf[2] ^ buf[3]; - if (port->write(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (stm32_get_ack(stm) != STM32_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (port->read(port, buf, 5) != PORT_ERR_OK) - return STM32_ERR_UNKNOWN; - - if (buf[4] != (buf[0] ^ buf[1] ^ buf[2] ^ buf[3])) - return STM32_ERR_UNKNOWN; - - *crc = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; - return STM32_ERR_OK; -} - -/* - * CRC computed by STM32 is similar to the standard crc32_be() - * implemented, for example, in Linux kernel in ./lib/crc32.c - * But STM32 computes it on units of 32 bits word and swaps the - * bytes of the word before the computation. - * Due to byte swap, I cannot use any CRC available in existing - * libraries, so here is a simple not optimized implementation. - */ -#define CRCPOLY_BE 0x04c11db7 -#define CRC_MSBMASK 0x80000000 -#define CRC_INIT_VALUE 0xFFFFFFFF -uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len) -{ - int i; - uint32_t data; - - if (len & 0x3) { - fprintf(stderr, "Buffer length must be multiple of 4 bytes\n"); - return 0; - } - - while (len) { - data = *buf++; - data |= *buf++ << 8; - data |= *buf++ << 16; - data |= *buf++ << 24; - len -= 4; - - crc ^= data; - - for (i = 0; i < 32; i++) - if (crc & CRC_MSBMASK) - crc = (crc << 1) ^ CRCPOLY_BE; - else - crc = (crc << 1); - } - return crc; -} - -stm32_err_t stm32_crc_wrapper(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc) -{ - uint8_t buf[256]; - uint32_t start, total_len, len, current_crc; - - if (address & 0x3 || length & 0x3) { - fprintf(stderr, "Start and end addresses must be 4 byte aligned\n"); - return STM32_ERR_UNKNOWN; - } - - if (stm->cmd->crc != STM32_CMD_ERR) - return stm32_crc_memory(stm, address, length, crc); - - start = address; - total_len = length; - current_crc = CRC_INIT_VALUE; - while (length) { - len = length > 256 ? 256 : length; - if (stm32_read_memory(stm, address, buf, len) != STM32_ERR_OK) { - fprintf(stderr, - "Failed to read memory at address 0x%08x, target write-protected?\n", - address); - return STM32_ERR_UNKNOWN; - } - current_crc = stm32_sw_crc(current_crc, buf, len); - length -= len; - address += len; - - fprintf(stderr, - "\rCRC address 0x%08x (%.2f%%) ", - address, - (100.0f / (float)total_len) * (float)(address - start) - ); - fflush(stderr); - } - fprintf(stderr, "Done.\n"); - *crc = current_crc; - return STM32_ERR_OK; -} diff --git a/win/src/stm32flash_serial/src/stm32.h b/win/src/stm32flash_serial/src/stm32.h deleted file mode 100644 index 1688fcb4b..000000000 --- a/win/src/stm32flash_serial/src/stm32.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _STM32_H -#define _STM32_H - -#include -#include "serial.h" - -#define STM32_MAX_RX_FRAME 256 /* cmd read memory */ -#define STM32_MAX_TX_FRAME (1 + 256 + 1) /* cmd write memory */ - -typedef enum { - STM32_ERR_OK = 0, - STM32_ERR_UNKNOWN, /* Generic error */ - STM32_ERR_NACK, - STM32_ERR_NO_CMD, /* Command not available in bootloader */ -} stm32_err_t; - -typedef struct stm32 stm32_t; -typedef struct stm32_cmd stm32_cmd_t; -typedef struct stm32_dev stm32_dev_t; - -struct stm32 { - const serial_t *serial; - struct port_interface *port; - uint8_t bl_version; - uint8_t version; - uint8_t option1, option2; - uint16_t pid; - stm32_cmd_t *cmd; - const stm32_dev_t *dev; -}; - -struct stm32_dev { - uint16_t id; - const char *name; - uint32_t ram_start, ram_end; - uint32_t fl_start, fl_end; - uint16_t fl_pps; // pages per sector - uint16_t fl_ps; // page size - uint32_t opt_start, opt_end; - uint32_t mem_start, mem_end; -}; - -stm32_t *stm32_init(struct port_interface *port, const char init); -void stm32_close(stm32_t *stm); -stm32_err_t stm32_read_memory(const stm32_t *stm, uint32_t address, - uint8_t data[], unsigned int len); -stm32_err_t stm32_write_memory(const stm32_t *stm, uint32_t address, - const uint8_t data[], unsigned int len); -stm32_err_t stm32_wunprot_memory(const stm32_t *stm); -stm32_err_t stm32_wprot_memory(const stm32_t *stm); -stm32_err_t stm32_erase_memory(const stm32_t *stm, uint8_t spage, - uint8_t pages); -stm32_err_t stm32_go(const stm32_t *stm, uint32_t address); -stm32_err_t stm32_reset_device(const stm32_t *stm); -stm32_err_t stm32_readprot_memory(const stm32_t *stm); -stm32_err_t stm32_runprot_memory(const stm32_t *stm); -stm32_err_t stm32_crc_memory(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc); -stm32_err_t stm32_crc_wrapper(const stm32_t *stm, uint32_t address, - uint32_t length, uint32_t *crc); -uint32_t stm32_sw_crc(uint32_t crc, uint8_t *buf, unsigned int len); - -#endif - diff --git a/win/src/stm32flash_serial/src/stm32flash.1 b/win/src/stm32flash_serial/src/stm32flash.1 deleted file mode 100644 index d37292f6a..000000000 --- a/win/src/stm32flash_serial/src/stm32flash.1 +++ /dev/null @@ -1,407 +0,0 @@ -.TH STM32FLASH 1 "2013\-11\-03" STM32FLASH "User command" -.SH NAME -stm32flash \- flashing utility for STM32 and STM32W through UART or I2C -.SH SYNOPSIS -.B stm32flash -.RB [ \-cfhjkouvCR ] -.RB [ \-a -.IR bus_address ] -.RB [ \-b -.IR baud_rate ] -.RB [ \-m -.IR serial_mode ] -.RB [ \-r -.IR filename ] -.RB [ \-w -.IR filename ] -.RB [ \-e -.IR num ] -.RB [ \-n -.IR count ] -.RB [ \-g -.IR address ] -.RB [ \-s -.IR start_page ] -.RB [ \-S -.IR address [: length ]] -.RB [ \-F -.IR RX_length [: TX_length ]] -.RB [ \-i -.IR GPIO_string ] -.RI [ tty_device -.R | -.IR i2c_device ] - -.SH DESCRIPTION -.B stm32flash -reads or writes the flash memory of STM32 and STM32W. - -It requires the STM32[W] to embed a bootloader compliant with ST -application note AN3155. -.B stm32flash -uses the serial port -.I tty_device -to interact with the bootloader of STM32[W]. - -.SH OPTIONS -.TP -.BI "\-a" " bus_address" -Specify address on bus for -.IR i2c_device . -This option is mandatory for I2C interface. - -.TP -.BI "\-b" " baud_rate" -Specify baud rate speed of -.IR tty_device . -Please notice that the ST bootloader can automatically detect the baud rate, -as explaned in chapter 2 of AN3155. -This option could be required together with option -.B "\-c" -or if following interaction with bootloader is expected. -Default is -.IR 57600 . - -.TP -.BI "\-m" " mode" -Specify the format of UART data. -.I mode -is a three characters long string where each character specifies, in -this strict order, character size, parity and stop bits. -The only values currenly used are -.I 8e1 -for standard STM32 bootloader and -.I 8n1 -for standard STM32W bootloader. -Default is -.IR 8e1 . - -.TP -.BI "\-r" " filename" -Specify to read the STM32[W] flash and write its content in -.I filename -in raw binary format (see below -.BR "FORMAT CONVERSION" ). - -.TP -.BI "\-w" " filename" -Specify to write the STM32[W] flash with the content of -.IR filename . -File format can be either raw binary or intel hex (see below -.BR "FORMAT CONVERSION" ). -The file format is automatically detected. -To by\-pass format detection and force binary mode (e.g. to -write an intel hex content in STM32[W] flash), use -.B \-f -option. - -.TP -.B \-u -Specify to disable write\-protection from STM32[W] flash. -The STM32[W] will be reset after this operation. - -.TP -.B \-j -Enable the flash read\-protection. - -.TP -.B \-k -Disable the flash read\-protection. - -.TP -.B \-o -Erase only. - -.TP -.BI "\-e" " num" -Specify to erase only -.I num -pages before writing the flash. Default is to erase the whole flash. With -.B \-e 0 -the flash would not be erased. - -.TP -.B \-v -Specify to verify flash content after write operation. - -.TP -.BI "\-n" " count" -Specify to retry failed writes up to -.I count -times. Default is 10 times. - -.TP -.BI "\-g" " address" -Specify address to start execution from (0 = flash start). - -.TP -.BI "\-s" " start_page" -Specify flash page offset (0 = flash start). - -.TP -.BI "\-S" " address" "[:" "length" "]" -Specify start address and optionally length for read/write/erase/crc operations. - -.TP -.BI "\-F" " RX_length" "[:" "TX_length" "]" -Specify the maximum frame size for the current interface. -Due to STM32 bootloader protocol, host will never handle frames bigger than -256 byte in RX or 258 byte in TX. -Due to current code, lowest limit in RX is 20 byte (to read a complete reply -of command GET). Minimum limit in TX is 5 byte, required by protocol. - -.TP -.B \-f -Force binary parser while reading file with -.BR "\-w" "." - -.TP -.B \-h -Show help. - -.TP -.B \-c -Specify to resume the existing UART connection and don't send initial -INIT sequence to detect baud rate. Baud rate must be kept the same as the -existing connection. This is useful if the reset fails. - -.TP -.BI "\-i" " GPIO_string" -Specify the GPIO sequences on the host to force STM32[W] to enter and -exit bootloader mode. GPIO can either be real GPIO connected from host to -STM32[W] beside the UART connection, or UART's modem signals used as -GPIO. (See below -.B BOOTLOADER GPIO SEQUENCE -for the format of -.I GPIO_string -and further explanation). - -.TP -.B \-C -Specify to compute CRC on memory content. -By default the CRC is computed on the whole flash content. -Use -.B "\-S" -to provide different memory address range. - -.TP -.B \-R -Specify to reset the device at exit. -This option is ignored if either -.BR "\-g" "," -.BR "\-j" "," -.B "\-k" -or -.B "\-u" -is also specified. - -.SH BOOTLOADER GPIO SEQUENCE -This feature is currently available on Linux host only. - -As explained in ST application note AN2606, after reset the STM32 will -execute either the application program in user flash or the bootloader, -depending on the level applied at specific pins of STM32 during reset. - -STM32 bootloader is automatically activated by configuring the pins -BOOT0="high" and BOOT1="low" and then by applying a reset. -Application program in user flash is activated by configuring the pin -BOOT0="low" (the level on BOOT1 is ignored) and then by applying a reset. - -When GPIO from host computer are connected to either configuration and -reset pins of STM32, -.B stm32flash -can control the host GPIO to reset STM32 and to force execution of -bootloader or execution of application program. - -The sequence of GPIO values to entry to and exit from bootloader mode is -provided with command line option -.B "\-i" -.IR "GPIO_string" . - -.PD 0 -The format of -.IR "GPIO_string" " is:" -.RS -GPIO_string = [entry sequence][:[exit sequence]] -.P -sequence = [\-]n[,sequence] -.RE -.P -In the above sequences, negative numbers correspond to GPIO at "low" level; -numbers without sign correspond to GPIO at "high" level. -The value "n" can either be the GPIO number on the host system or the -string "rts", "dtr" or "brk". The strings "rts" and "dtr" drive the -corresponding UART's modem lines RTS and DTR as GPIO. -The string "brk" forces the UART to send a BREAK sequence on TX line; -after BREAK the UART is returned in normal "non\-break" mode. -Note: the string "\-brk" has no effect and is ignored. -.PD - -.PD 0 -As example, let's suppose the following connection between host and STM32: -.IP \(bu 2 -host GPIO_3 connected to reset pin of STM32; -.IP \(bu 2 -host GPIO_4 connected to STM32 pin BOOT0; -.IP \(bu 2 -host GPIO_5 connected to STM32 pin BOOT1. -.PD -.P - -In this case, the sequence to enter in bootloader mode is: first put -GPIO_4="high" and GPIO_5="low"; then send reset pulse by GPIO_3="low" -followed by GPIO_3="high". -The corresponding string for -.I GPIO_string -is "4,\-5,\-3,3". - -To exit from bootloade and run the application program, the sequence is: -put GPIO_4="low"; then send reset pulse. -The corresponding string for -.I GPIO_string -is "\-4,\-3,3". - -The complete command line flag is "\-i 4,\-5,\-3,3:\-4,\-3,3". - -STM32W uses pad PA5 to select boot mode; if during reset PA5 is "low" then -STM32W will enter in bootloader mode; if PA5 is "high" it will execute the -program in flash. - -As example, supposing GPIO_3 connected to PA5 and GPIO_2 to STM32W's reset. -The command: -.PD 0 -.RS -stm32flash \-i \-3,\-2,2:3,\-2,2 /dev/ttyS0 -.RE -provides: -.IP \(bu 2 -entry sequence: GPIO_3=low, GPIO_2=low, GPIO_2=high -.IP \(bu 2 -exit sequence: GPIO_3=high, GPIO_2=low, GPIO_2=high -.PD - -.SH EXAMPLES -Get device information: -.RS -.PD 0 -.P -stm32flash /dev/ttyS0 -.PD -.RE - -Write with verify and then start execution: -.RS -.PD 0 -.P -stm32flash \-w filename \-v \-g 0x0 /dev/ttyS0 -.PD -.RE - -Read flash to file: -.RS -.PD 0 -.P -stm32flash \-r filename /dev/ttyS0 -.PD -.RE - -Start execution: -.RS -.PD 0 -.P -stm32flash \-g 0x0 /dev/ttyS0 -.PD -.RE - -Specify: -.PD 0 -.IP \(bu 2 -entry sequence: RTS=low, DTR=low, DTR=high -.IP \(bu 2 -exit sequence: RTS=high, DTR=low, DTR=high -.P -.RS -stm32flash \-i \-rts,\-dtr,dtr:rts,\-dtr,dtr /dev/ttyS0 -.PD -.RE - -.SH FORMAT CONVERSION -Flash images provided by ST or created with ST tools are often in file -format Motorola S\-Record. -Conversion between raw binary, intel hex and Motorola S\-Record can be -done through software package SRecord. - -.SH AUTHORS -The original software package -.B stm32flash -is written by -.I Geoffrey McRae -and is since 2012 maintained by -.IR "Tormod Volden " . - -Man page and extension to STM32W and I2C are written by -.IR "Antonio Borneo " . - -Please report any bugs at the project homepage -http://stm32flash.googlecode.com . - -.SH SEE ALSO -.BR "srec_cat" "(1)," " srec_intel" "(5)," " srec_motorola" "(5)." - -The communication protocol used by ST bootloader is documented in -following ST application notes, depending on communication port. -The current version of -.B stm32flash -only supports -.I UART -and -.I I2C -ports. -.PD 0 -.P -.IP \(bu 2 -AN3154: CAN protocol used in the STM32 bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/CD00264321.pdf -.RE - -.P -.IP \(bu 2 -AN3155: USART protocol used in the STM32(TM) bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/CD00264342.pdf -.RE - -.P -.IP \(bu 2 -AN4221: I2C protocol used in the STM32 bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/DM00072315.pdf -.RE - -.P -.IP \(bu 2 -AN4286: SPI protocol used in the STM32 bootloader -.P -.RS -http://www.st.com/web/en/resource/technical/document/application_note/DM00081379.pdf -.RE - -.PD - - -Boot mode selection for STM32 is documented in ST application note -AN2606, available from the ST website: -.PD 0 -.P -http://www.st.com/web/en/resource/technical/document/application_note/CD00167594.pdf -.PD - -.SH LICENSE -.B stm32flash -is distributed under GNU GENERAL PUBLIC LICENSE Version 2. -Copy of the license is available within the source code in the file -.IR "gpl\-2.0.txt" . diff --git a/win/src/stm32flash_serial/src/utils.c b/win/src/stm32flash_serial/src/utils.c deleted file mode 100644 index 271bb3ed7..000000000 --- a/win/src/stm32flash_serial/src/utils.c +++ /dev/null @@ -1,45 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#include -#include "utils.h" - -/* detect CPU endian */ -char cpu_le() { - const uint32_t cpu_le_test = 0x12345678; - return ((const unsigned char*)&cpu_le_test)[0] == 0x78; -} - -uint32_t be_u32(const uint32_t v) { - if (cpu_le()) - return ((v & 0xFF000000) >> 24) | - ((v & 0x00FF0000) >> 8) | - ((v & 0x0000FF00) << 8) | - ((v & 0x000000FF) << 24); - return v; -} - -uint32_t le_u32(const uint32_t v) { - if (!cpu_le()) - return ((v & 0xFF000000) >> 24) | - ((v & 0x00FF0000) >> 8) | - ((v & 0x0000FF00) << 8) | - ((v & 0x000000FF) << 24); - return v; -} diff --git a/win/src/stm32flash_serial/src/utils.h b/win/src/stm32flash_serial/src/utils.h deleted file mode 100644 index a8d37d2d5..000000000 --- a/win/src/stm32flash_serial/src/utils.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - stm32flash - Open Source ST STM32 flash program for *nix - Copyright (C) 2010 Geoffrey McRae - - 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 2 - 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, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - - -#ifndef _H_UTILS -#define _H_UTILS - -#include - -char cpu_le(); -uint32_t be_u32(const uint32_t v); -uint32_t le_u32(const uint32_t v); - -#endif From 550b232b6d952e47e38bff2017c04c3a66725235 Mon Sep 17 00:00:00 2001 From: "Frederic.Pillon" Date: Fri, 21 Sep 2018 12:21:26 +0200 Subject: [PATCH 2/2] [stm32flash] update to version STM32duino_0.5.1 https://github.com/stm32duino/stm32flash Signed-off-by: Frederic.Pillon --- linux/stm32flash/stm32flash | Bin 88981 -> 58984 bytes linux64/stm32flash/stm32flash | Bin 97399 -> 70406 bytes macosx/stm32flash/stm32flash | Bin 70448 -> 74532 bytes win/stm32flash.exe | Bin 160128 -> 205843 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/linux/stm32flash/stm32flash b/linux/stm32flash/stm32flash index 16872bba61573f09112823df05c9f4bc61d2dabd..21abb6e38ffefd98e67bbf16559e9a1d067b67aa 100755 GIT binary patch literal 58984 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 literal 88981 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 B!><4U diff --git a/linux64/stm32flash/stm32flash b/linux64/stm32flash/stm32flash index 7e067aee07cd7325b3db4977811dab8d6f0714d7..f1a848ded079f3b220cfcc692e59e47f5ba4d035 100755 GIT binary patch literal 70406 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 Ta;Z>A_4T+J3V2LP`h@=jl%YXY literal 97399 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 diff --git a/macosx/stm32flash/stm32flash b/macosx/stm32flash/stm32flash index dc8d422416d4c0db8853666ea112f02f77ad9ff8..8176d233ef40d1e35aaf542dff4dc78e06ec550a 100755 GIT binary patch literal 74532 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%0A75!~2%O_Oyh*?t69a7({=vrX7 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 ZD&k!#!T)uQ_TDd$LO*WT&Kqtl{s+zjiHZOK literal 70448 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 diff --git a/win/stm32flash.exe b/win/stm32flash.exe index 911c0cc058b8b9d40cb95e9d83223b998c9f673a..d48eddec6f24bbd66e47a6af418cb11389d5754f 100644 GIT binary patch literal 205843 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

3EY)i#kt`3Oy1sure`(nT3X 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%0Auju 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 literal 160128 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%0AW7~xNms>5VlFUgHupA)B&5qafSAnsih&uI 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�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®4CdUR1`_XP!ETtJB0^;bypE;mTD@ zR>p5xcIU#Cb(#{goJ_}p7Dq4G?wLBmBTXV2RDu%~xaPxoLm-K&ot7C4!xr42YU6+w zvVxGd*s_JIeGPodew=~!;Bf;&O7f*k)?m1l$jD5hH3)Ykaw07~5hQ%HO6W+()9LVl zG&kZ|W&-7qRUEj9G%fl@ZE((T_&G(n=*aF?bftpMqHw1fG9IOjV{RVLY{us=H9tKa zlI+!uDcPJfGb~>EoubTNjoNO=fef3~n9d^bMDR*N`7Uts4M`KoS}L9!bK{xn;|3(I z8(LUBpV9A#MFcq^azHU{;)t~ z>u~2ULp2jvBpzSZhGcOI3Kr=VsT66C9MppuN(V^n zcaeklt9m?!5ntd2#D^L@=_Ond#KD@PXb{;nS3&ilCU>x|I-HE|xN=Q8bQ)97E&hL{ C5*^3@