├── .circleci
└── config.yml
├── .gitignore
├── .gitmodules
├── .vscode
└── settings.json
├── LICENSE
├── README.md
├── release.Makefile
├── src
├── Makefile
├── blink
│ ├── Makefile
│ ├── blink.c
│ ├── stm32f103x8.ld
│ └── uf2conv.py
├── bmp.sh
├── dapboot.c
├── dapboot.h
├── debug.cfg
├── dmesg.c
├── dmesg.h
├── dummy.c
├── gdb.sh
├── ghostfat.c
├── rules.mk
├── run.sh
├── stm32f103
│ ├── backup.c
│ ├── backup.h
│ ├── bluepill
│ │ └── config.h
│ ├── generic
│ │ └── config.h
│ ├── jacdac
│ │ └── config.h
│ ├── maplemini
│ │ └── config.h
│ ├── pxt32
│ │ └── config.h
│ ├── stlink
│ │ └── config.h
│ ├── stm32f103x8.ld
│ └── target_stm32f103.c
├── target.h
├── targets.mk
├── uf2.h
├── uf2cfg.h
├── usb_conf.c
├── usb_conf.h
├── usb_msc.c
├── webusb.c
├── webusb.h
├── webusb_defs.h
├── winusb.c
├── winusb.h
└── winusb_defs.h
└── util
└── install-toolchain.sh
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | machine: true
5 | steps:
6 | - checkout
7 | - run:
8 | name: Checkout submodules
9 | command: git submodule sync && git submodule update --init
10 | - restore_cache:
11 | key: v1-toolchain-checksum-{{ checksum "util/install-toolchain.sh" }}
12 | - run:
13 | name: Install toolchain
14 | command: ./util/install-toolchain.sh
15 | - save_cache:
16 | key: v1-toolchain-checksum-{{ checksum "util/install-toolchain.sh" }}
17 | paths:
18 | - "~/toolchains/"
19 | - run:
20 | name: Compile firmware
21 | command: make -f release.Makefile -k all
22 | environment:
23 | PREFIX: "~/toolchains/gcc-arm-embedded/bin/arm-none-eabi"
24 | - store_artifacts:
25 | path: build/
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # ignore GNU global files
2 | GPATH
3 | GRTAGS
4 | GSYMS
5 | GTAGS
6 |
7 | # ignore build artifacts
8 | *.d
9 | *.o
10 | *.bin
11 | *.hex
12 | *.elf
13 | *.axf
14 | *.map
15 | *.uf2
16 |
17 | build
18 |
19 | # ignore local makefile settings
20 | src/local.mk
21 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "libopencm3"]
2 | path = libopencm3
3 | url = https://github.com/devanlai/libopencm3.git
4 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "files.exclude": {
3 | "libopencm3/tests/gadget-zero/**/openocd.*.local.cfg": true,
4 | "libopencm3/**/*.d": true,
5 | "libopencm3/**/*.o": true,
6 | "libopencm3/**/*.bin": true,
7 | "libopencm3/**/*.hex": true,
8 | "libopencm3/**/*.list": true,
9 | "libopencm3/**/*.srec": true,
10 | "libopencm3/**/*.a": true,
11 | "libopencm3/**/*.elf": true,
12 | "libopencm3/lib/*.ld": true,
13 | "libopencm3/**/*.stylecheck": true,
14 | "libopencm3/**/*.swp": true,
15 | "libopencm3/**/\\#*": true,
16 | "libopencm3/**/.\\#*": true,
17 | "libopencm3/**/*~": true,
18 | "libopencm3/**/*.map": true,
19 | "libopencm3/**/*.log": true,
20 | "libopencm3/html/": true,
21 | "libopencm3/latex/": true,
22 | "libopencm3/**/*.pdf": true,
23 | "libopencm3/**/*.tag": true,
24 | "libopencm3/**/.DS_Store": true,
25 | "libopencm3/include/libopencm3/**/nvic.h": true,
26 | "libopencm3/include/libopencm3/**/**/nvic.h": true,
27 | "libopencm3/lib/**/vector_nvic.c": true,
28 | "libopencm3/lib/**/**/vector_nvic.c": true,
29 | "libopencm3/include/libopencmsis/efm32/": true,
30 | "libopencm3/include/libopencmsis/lm3s/": true,
31 | "libopencm3/include/libopencmsis/lpc13xx/": true,
32 | "libopencm3/include/libopencmsis/lpc17xx/": true,
33 | "libopencm3/include/libopencmsis/lpc43xx/": true,
34 | "libopencm3/include/libopencmsis/sam/": true,
35 | "libopencm3/include/libopencmsis/stm32/": true,
36 | "libopencm3/include/libopencmsis/vf6xx/": true,
37 | "libopencm3/nbproject/": true,
38 | "libopencm3/.idea/": true,
39 | "libopencm3/**/.project": true,
40 | "libopencm3/**/cscope.out": true,
41 | "**/GPATH": true,
42 | "**/GRTAGS": true,
43 | "**/GSYMS": true,
44 | "**/GTAGS": true,
45 | "**/*.d": true,
46 | "**/*.o": true,
47 | "**/*.bin": true,
48 | "**/*.hex": true,
49 | "**/*.elf": true,
50 | "**/*.axf": true,
51 | "**/*.map": true,
52 | "src/local.mk": true
53 | },
54 | "files.associations": {
55 | "vector.h": "c",
56 | "cortex.h": "c",
57 | "rtc.h": "c"
58 | }
59 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | With the exception of files that contain licensing information
2 | stating the contrary, files within the dapboot project are licensed
3 | under the ISC license as follows:
4 |
5 | Copyright (c) 2016, Devan Lai
6 |
7 | Permission to use, copy, modify, and/or distribute this software
8 | for any purpose with or without fee is hereby granted, provided
9 | that the above copyright notice and this permission notice
10 | appear in all copies.
11 |
12 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
13 | WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
14 | WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
15 | AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
16 | CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
17 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
18 | NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
19 | CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 |
21 | The following files in the dapboot project pertaining to the base
22 | Makefile and linker script are derived from the libopencm3 examples
23 | template and are licensed under the GNU Lesser General Public
24 | License version 3:
25 | * libopencm3.rules.mk
26 | * src/libopencm3.target.mk
27 | * src/stm32f042/stm32f042x6.ld
28 | * src/stm32f103/stm32f103x8.ld
29 |
30 | libopencm3, included as a submodule and statically linked as part
31 | of the build process, is separately licensed under the LGPLv3.
32 |
33 | The following is for informative purposes only: all LICENSE files
34 | contained within the project should be consulted for precise
35 | specifications.
36 |
37 | The LGLPv3 is the most restrictive license applying to any subset
38 | of the dapboot project; all other licensed material is strictly less
39 | restrictive than the LGPLv3. Accordingly, you may distribute the
40 | dapboot project in source or object code form under the terms of
41 | the LGPLv3 without needing to meet additional requirements for
42 | the less restrictively licensed portions of the dapboot project.
43 |
44 | Otherwise, the combined work consisting of the dapboot object code
45 | linked with the libopencm3 object code may be distributed without
46 | distributing a copy of the dapboot source code or any modifications
47 | to it.
48 |
49 | However, if the source code is not distributed, you must provide a
50 | means for the user to "re-link" the libopencm3 object code to
51 | produce a new combined work containing updated libopencm3 object
52 | code along-side any dapboot object code.
53 |
54 | The text of the GNU Lesser General Public License version 3 is
55 | reproduced below for use with the limited portions of the dapboot
56 | project licensed under the LGPLv3:
57 |
58 | GNU LESSER GENERAL PUBLIC LICENSE
59 | Version 3, 29 June 2007
60 |
61 | Copyright (C) 2007 Free Software Foundation, Inc.
62 | Everyone is permitted to copy and distribute verbatim copies
63 | of this license document, but changing it is not allowed.
64 |
65 |
66 | This version of the GNU Lesser General Public License incorporates
67 | the terms and conditions of version 3 of the GNU General Public
68 | License, supplemented by the additional permissions listed below.
69 |
70 | 0. Additional Definitions.
71 |
72 | As used herein, "this License" refers to version 3 of the GNU Lesser
73 | General Public License, and the "GNU GPL" refers to version 3 of the GNU
74 | General Public License.
75 |
76 | "The Library" refers to a covered work governed by this License,
77 | other than an Application or a Combined Work as defined below.
78 |
79 | An "Application" is any work that makes use of an interface provided
80 | by the Library, but which is not otherwise based on the Library.
81 | Defining a subclass of a class defined by the Library is deemed a mode
82 | of using an interface provided by the Library.
83 |
84 | A "Combined Work" is a work produced by combining or linking an
85 | Application with the Library. The particular version of the Library
86 | with which the Combined Work was made is also called the "Linked
87 | Version".
88 |
89 | The "Minimal Corresponding Source" for a Combined Work means the
90 | Corresponding Source for the Combined Work, excluding any source code
91 | for portions of the Combined Work that, considered in isolation, are
92 | based on the Application, and not on the Linked Version.
93 |
94 | The "Corresponding Application Code" for a Combined Work means the
95 | object code and/or source code for the Application, including any data
96 | and utility programs needed for reproducing the Combined Work from the
97 | Application, but excluding the System Libraries of the Combined Work.
98 |
99 | 1. Exception to Section 3 of the GNU GPL.
100 |
101 | You may convey a covered work under sections 3 and 4 of this License
102 | without being bound by section 3 of the GNU GPL.
103 |
104 | 2. Conveying Modified Versions.
105 |
106 | If you modify a copy of the Library, and, in your modifications, a
107 | facility refers to a function or data to be supplied by an Application
108 | that uses the facility (other than as an argument passed when the
109 | facility is invoked), then you may convey a copy of the modified
110 | version:
111 |
112 | a) under this License, provided that you make a good faith effort to
113 | ensure that, in the event an Application does not supply the
114 | function or data, the facility still operates, and performs
115 | whatever part of its purpose remains meaningful, or
116 |
117 | b) under the GNU GPL, with none of the additional permissions of
118 | this License applicable to that copy.
119 |
120 | 3. Object Code Incorporating Material from Library Header Files.
121 |
122 | The object code form of an Application may incorporate material from
123 | a header file that is part of the Library. You may convey such object
124 | code under terms of your choice, provided that, if the incorporated
125 | material is not limited to numerical parameters, data structure
126 | layouts and accessors, or small macros, inline functions and templates
127 | (ten or fewer lines in length), you do both of the following:
128 |
129 | a) Give prominent notice with each copy of the object code that the
130 | Library is used in it and that the Library and its use are
131 | covered by this License.
132 |
133 | b) Accompany the object code with a copy of the GNU GPL and this license
134 | document.
135 |
136 | 4. Combined Works.
137 |
138 | You may convey a Combined Work under terms of your choice that,
139 | taken together, effectively do not restrict modification of the
140 | portions of the Library contained in the Combined Work and reverse
141 | engineering for debugging such modifications, if you also do each of
142 | the following:
143 |
144 | a) Give prominent notice with each copy of the Combined Work that
145 | the Library is used in it and that the Library and its use are
146 | covered by this License.
147 |
148 | b) Accompany the Combined Work with a copy of the GNU GPL and this license
149 | document.
150 |
151 | c) For a Combined Work that displays copyright notices during
152 | execution, include the copyright notice for the Library among
153 | these notices, as well as a reference directing the user to the
154 | copies of the GNU GPL and this license document.
155 |
156 | d) Do one of the following:
157 |
158 | 0) Convey the Minimal Corresponding Source under the terms of this
159 | License, and the Corresponding Application Code in a form
160 | suitable for, and under terms that permit, the user to
161 | recombine or relink the Application with a modified version of
162 | the Linked Version to produce a modified Combined Work, in the
163 | manner specified by section 6 of the GNU GPL for conveying
164 | Corresponding Source.
165 |
166 | 1) Use a suitable shared library mechanism for linking with the
167 | Library. A suitable mechanism is one that (a) uses at run time
168 | a copy of the Library already present on the user's computer
169 | system, and (b) will operate properly with a modified version
170 | of the Library that is interface-compatible with the Linked
171 | Version.
172 |
173 | e) Provide Installation Information, but only if you would otherwise
174 | be required to provide such information under section 6 of the
175 | GNU GPL, and only to the extent that such information is
176 | necessary to install and execute a modified version of the
177 | Combined Work produced by recombining or relinking the
178 | Application with a modified version of the Linked Version. (If
179 | you use option 4d0, the Installation Information must accompany
180 | the Minimal Corresponding Source and Corresponding Application
181 | Code. If you use option 4d1, you must provide the Installation
182 | Information in the manner specified by section 6 of the GNU GPL
183 | for conveying Corresponding Source.)
184 |
185 | 5. Combined Libraries.
186 |
187 | You may place library facilities that are a work based on the
188 | Library side by side in a single library together with other library
189 | facilities that are not Applications and are not covered by this
190 | License, and convey such a combined library under terms of your
191 | choice, if you do both of the following:
192 |
193 | a) Accompany the combined library with a copy of the same work based
194 | on the Library, uncombined with any other library facilities,
195 | conveyed under the terms of this License.
196 |
197 | b) Give prominent notice with the combined library that part of it
198 | is a work based on the Library, and explaining where to find the
199 | accompanying uncombined form of the same work.
200 |
201 | 6. Revised Versions of the GNU Lesser General Public License.
202 |
203 | The Free Software Foundation may publish revised and/or new versions
204 | of the GNU Lesser General Public License from time to time. Such new
205 | versions will be similar in spirit to the present version, but may
206 | differ in detail to address new problems or concerns.
207 |
208 | Each version is given a distinguishing version number. If the
209 | Library as you received it specifies that a certain numbered version
210 | of the GNU Lesser General Public License "or any later version"
211 | applies to it, you have the option of following the terms and
212 | conditions either of that published version or of any later version
213 | published by the Free Software Foundation. If the Library as you
214 | received it does not specify a version number of the GNU Lesser
215 | General Public License, you may choose any version of the GNU Lesser
216 | General Public License ever published by the Free Software Foundation.
217 |
218 | If the Library as you received it specifies that a proxy can decide
219 | whether future versions of the GNU Lesser General Public License shall
220 | apply, that proxy's public statement of acceptance of any version is
221 | permanent authorization for you to choose that version for the
222 | Library.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # UF2 bootloader for STM32F103
2 |
3 | This project was initially forked off https://github.com/devanlai/dapboot though the DFU functionality has been removed
4 | and replaced with a USB Mass Storage with [UF2 support](https://github.com/Microsoft/uf2)
5 |
6 | Boards with this bootloader can be programmed at https://maker.makecode.com
7 | using web interface using a graphical programming language or TypeScript (JavaScript with Types).
8 |
9 | ## Flashing bootloader from binaries
10 |
11 | You will need a STLink/v2 (or other debugger) to flash it.
12 |
13 | * https://github.com/mmoskal/uf2-stm32f103/releases
14 | * download the latest ZIP file (`uf2-stm32f103-vX.Y.Z.zip`)
15 | * run: `openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c "program uf2boot-BLUEPILL.bin verify reset exit 0x8000000"`
16 | * see if `BLUEPILL` drive appears; if not reset the board; the LED should be fading in and out about once per second
17 |
18 | ## Build instructions
19 | The default target is a generic STM32F103 dev board with an LED on PC13, commonly referred to as a "bluepill" board.
20 |
21 | To build other targets, you can override the
22 | `TARGET` variable when invoking `make`.
23 |
24 | make clean
25 | make TARGET=STLINK
26 |
27 | ### Targets
28 |
29 | | Target Name | Description | Link |
30 | | ----------- | ----------- |----- |
31 | |`BLUEPILL` | Cheap dev board | http://wiki.stm32duino.com/index.php?title=Blue_Pill |
32 | |`MAPLEMINI` | LeafLabs Maple Mini board and clone derivatives | http://wiki.stm32duino.com/index.php?title=Maple_Mini |
33 | |`STLINK` | STLink/v2 hardware clones | https://wiki.paparazziuav.org/wiki/STLink#Clones |
34 | | `PXT32` | MakeCode Arcade console (currently disabled on Arcade site) | https://arcade.makecode.com |
35 |
36 |
37 | ## Flash instructions
38 |
39 | The `make flash` target will use openocd to upload the bootloader to an attached board.
40 | By default, the Makefile assumes you're using a STLink v2 based probe, but you can override this by overriding `OOCD_INTERFACE` variable. For example:
41 |
42 | make OOCD_INTERFACE=interface/cmsis-dap.cfg flash
43 |
44 | ## Overriding defaults
45 | Local makefile settings can be set by creating a `local.mk`, which is automatically included.
46 |
47 | Here is an example `local.mk` that changes the default target to the STLink/v2 and uses an unmodified STLink/v2 to flash it.
48 |
49 | TARGET ?= STLINK
50 | OOCD_INTERFACE ?= interface/stlink-v2.cfg
51 |
52 | ## Using the bootloader
53 | ### Building for the bootloader
54 | The bootloader occupies the lower 16KiB of flash, so your application must offset its flash contents by 16KiB. This can be done by modifying your linker script or flags as appropriate.
55 |
56 | ### Switching to the bootloader
57 | The bootloader can be built to look for arbitrary patterns, but the default for the STM32F103 target looks for a magic value stored in the RTC backup registers. Writing the magic value and then resetting will run the bootloader instead of the main application.
58 |
59 | ### WebUSB
60 |
61 | The WebUSB isn't currently supported.
62 |
63 | ## Licensing
64 | All contents of the dapboot project are licensed under terms that are compatible with the terms of the GNU Lesser General Public License version 3.
65 |
66 | Non-libopencm3 related portions of the dapboot project are licensed under the less restrictive ISC license, except where otherwise specified in the headers of specific files.
67 |
68 | The UF2 parts are licensed under MIT.
69 |
70 | See the LICENSE file for full details.
71 |
--------------------------------------------------------------------------------
/release.Makefile:
--------------------------------------------------------------------------------
1 | ## Copyright (c) 2017, Devan Lai
2 | ##
3 | ## Permission to use, copy, modify, and/or distribute this software
4 | ## for any purpose with or without fee is hereby granted, provided
5 | ## that the above copyright notice and this permission notice
6 | ## appear in all copies.
7 | ##
8 | ## THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
9 | ## WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
10 | ## WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
11 | ## AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
12 | ## CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 | ## LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
14 | ## NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15 | ## CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 |
17 | # This Makefile builds all official targets and places the firmware
18 | # bin files in the build/ directory.
19 | #
20 | # For normal development, use the Makefile in the src/ directory.
21 |
22 | # Be silent per default, but 'make V=1' will show all compiler calls.
23 | ifneq ($(V),1)
24 | Q := @
25 | NULL := 2>/dev/null
26 | MAKE := $(MAKE) --no-print-directory
27 | endif
28 | export V
29 |
30 | BUILD_DIR ?= ./build
31 |
32 | all: dapboot-bluepill.bin \
33 | dapboot-maplemini.bin \
34 | dapboot-stlink.bin
35 |
36 | clean:
37 | $(Q)$(RM) $(BUILD_DIR)/*.bin
38 | $(Q)$(MAKE) -C src/ clean
39 |
40 | .PHONY = all clean
41 |
42 | $(BUILD_DIR):
43 | $(Q)mkdir -p $(BUILD_DIR)
44 |
45 | dapboot-bluepill.bin: | $(BUILD_DIR)
46 | @printf " BUILD $(@)\n"
47 | $(Q)$(MAKE) TARGET=BLUEPILL -C src/ clean
48 | $(Q)$(MAKE) TARGET=BLUEPILL -C src/
49 | $(Q)cp src/dapboot.bin $(BUILD_DIR)/$(@)
50 |
51 | dapboot-stlink.bin: | $(BUILD_DIR)
52 | @printf " BUILD $(@)\n"
53 | $(Q)$(MAKE) TARGET=STLINK -C src/ clean
54 | $(Q)$(MAKE) TARGET=STLINK -C src/
55 | $(Q)cp src/dapboot.bin $(BUILD_DIR)/$(@)
56 |
57 | dapboot-maplemini.bin: | $(BUILD_DIR)
58 | @printf " BUILD $(@)\n"
59 | $(Q)$(MAKE) TARGET=MAPLEMINI -C src/ clean
60 | $(Q)$(MAKE) TARGET=MAPLEMINI -C src/
61 | $(Q)cp src/dapboot.bin $(BUILD_DIR)/$(@)
62 |
--------------------------------------------------------------------------------
/src/Makefile:
--------------------------------------------------------------------------------
1 | ## Copyright (c) 2016, Devan Lai
2 | ##
3 | ## Permission to use, copy, modify, and/or distribute this software
4 | ## for any purpose with or without fee is hereby granted, provided
5 | ## that the above copyright notice and this permission notice
6 | ## appear in all copies.
7 | ##
8 | ## THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
9 | ## WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
10 | ## WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
11 | ## AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
12 | ## CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 | ## LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
14 | ## NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15 | ## CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 |
17 | -include local.mk
18 |
19 | BINARY = uf2boot
20 | OPENCM3_DIR = ../libopencm3
21 |
22 | UF2_VERSION_BASE = $(shell git describe --dirty --always --tags)
23 | VER_FLAGS = -DUF2_VERSION='"$(UF2_VERSION_BASE)"'
24 |
25 | TARGET ?= BLUEPILL
26 | include targets.mk
27 |
28 | SRCS := $(wildcard *.c)
29 | SRCS += $(wildcard $(TARGET_COMMON_DIR)/*.c)
30 | SRCS += $(wildcard $(TARGET_SPEC_DIR)/*.c)
31 |
32 | BUILD = build/$(TARGET)
33 |
34 | OBJS += $(addprefix $(BUILD)/,$(SRCS:.c=.o))
35 | DEPS = $(addprefix $(BUILD)/,$(SRCS:.c=.d))
36 |
37 | ELF = $(BUILD)/$(BINARY).elf
38 |
39 | all: $(BUILD) $(BUILD)/$(BINARY).bin size
40 |
41 | $(BUILD):
42 | mkdir -p $(BUILD)/stm32f103
43 |
44 | clean::
45 | rm -rf build/
46 |
47 | include rules.mk
48 |
49 | size: $(OBJS) $(ELF)
50 | @$(PREFIX)-size $(ELF)
51 |
52 | BMP = $(shell ls -1 /dev/cu.usbmodem* | head -1)
53 | BMP_ARGS = -ex "target extended-remote $(BMP)" -ex "mon swdp_scan" -ex "attach 1"
54 | GDB = arm-none-eabi-gdb
55 |
56 | flash: $(ELF)
57 | $(GDB) $(BMP_ARGS) -ex "load" -ex "quit" $(ELF)
58 |
59 | gdb: $(ELF)
60 | $(GDB) $(BMP_ARGS) $(ELF)
61 |
62 | ocd-gdb: $(ELF)
63 | -$(GDB) --eval "target remote | $(OOCD) -f $(OOCD_INTERFACE) -f $(OOCD_BOARD) -f debug.cfg" $(ELF)
64 |
65 | erase:
66 | $(OOCD) -f $(OOCD_INTERFACE) -f $(OOCD_BOARD) \
67 | -c "init" -c "reset init" \
68 | -c "stm32f1x unlock 0; reset halt" \
69 | -c "flash erase_sector 0 0 last" -c "reset" -c "shutdown"
70 |
71 | .PHONY += debug size erase
72 |
73 | OBJS := $(sort $(OBJS))
74 |
75 | # Add the base directory to the header search path
76 | CPPFLAGS += -I.
77 |
78 | # Add target config directory to the header search path
79 | CPPFLAGS += -I$(TARGET_COMMON_DIR)/
80 | CPPFLAGS += -I$(TARGET_SPEC_DIR)/
81 |
82 | DROPNAME = uf2-stm32f103-$(UF2_VERSION_BASE)
83 |
84 | do-drop: all
85 | mkdir -p build/$(DROPNAME)
86 | cp $(BUILD)/$(BINARY).bin build/$(DROPNAME)/$(BINARY)-$(TARGET).bin
87 |
88 | drop:
89 | rm -rf build
90 | set -e; for t in BLUEPILL JACDAC ; do $(MAKE) TARGET=$$t do-drop ; done
91 | cd build; 7z a $(DROPNAME).zip $(DROPNAME)
92 |
--------------------------------------------------------------------------------
/src/blink/Makefile:
--------------------------------------------------------------------------------
1 | ## Copyright (c) 2016, Devan Lai
2 | ##
3 | ## Permission to use, copy, modify, and/or distribute this software
4 | ## for any purpose with or without fee is hereby granted, provided
5 | ## that the above copyright notice and this permission notice
6 | ## appear in all copies.
7 | ##
8 | ## THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
9 | ## WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
10 | ## WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
11 | ## AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
12 | ## CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 | ## LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
14 | ## NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15 | ## CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 |
17 | -include ../local.mk
18 |
19 | BINARY = blink
20 | OPENCM3_DIR = ../../libopencm3
21 |
22 | TARGET ?= BLUEPILL
23 | include ../targets.mk
24 | LDSCRIPT := ./stm32f103x8.ld
25 |
26 | SRCS := $(wildcard *.c)
27 | SRCS += $(wildcard ../$(TARGET_COMMON_DIR)/*.c)
28 | SRCS += $(wildcard ../$(TARGET_SPEC_DIR)/*.c)
29 |
30 | OBJS += $(SRCS:.c=.o)
31 | DEPS = $(SRCS:.c=.d)
32 |
33 | .DEFAULT_GOAL := $(BINARY).uf2
34 |
35 | $(BINARY).uf2: $(BINARY).bin
36 | python uf2conv.py -c -b 0x08004000 -o "$@" "$<"
37 |
38 | clean::
39 | @rm -f $(OBJS)
40 | @rm -f $(DEPS)
41 |
42 | include ../rules.mk
43 |
44 | size: $(OBJS) $(BINARY).elf
45 | @$(PREFIX)-size $(OBJS) $(BINARY).elf
46 |
47 | debug: $(BINARY).elf
48 | -$(GDB) --eval "target remote | $(OOCD) -f $(OOCD_INTERFACE) -f $(OOCD_BOARD) -f debug.cfg" $(BINARY).elf
49 |
50 | .PHONY += debug size erase
51 |
52 | OBJS := $(sort $(OBJS))
53 |
54 | # Add the base directory to the header search path
55 | CPPFLAGS += -I..
56 |
57 | # Add target config directory to the header search path
58 | CPPFLAGS += -I../$(TARGET_COMMON_DIR)/
59 | CPPFLAGS += -I../$(TARGET_SPEC_DIR)/
60 |
--------------------------------------------------------------------------------
/src/blink/blink.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #include
20 | #include
21 | #include "target.h"
22 |
23 | static void delay(int n) {
24 | for (int i = 0; i < n*1000000; ++i)
25 | asm("nop");
26 | }
27 |
28 | int main(void) {
29 | /* Setup clocks */
30 | target_clock_setup();
31 |
32 | /* Initialize GPIO/LEDs if needed */
33 | target_gpio_setup();
34 |
35 | while (1) {
36 | target_set_led(1);
37 | delay(1);
38 | target_set_led(0);
39 | delay(1);
40 | }
41 |
42 | return 0;
43 | }
44 |
--------------------------------------------------------------------------------
/src/blink/stm32f103x8.ld:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the libopencm3 project.
3 | *
4 | * Copyright (C) 2015 Karl Palsson
5 | *
6 | * This library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this library. If not, see .
18 | */
19 |
20 | /* Linker script for STM32F103x8, 64k flash, 20k RAM. */
21 |
22 | /* Define memory regions. */
23 | /* 8k for the bootloader */
24 | MEMORY
25 | {
26 | rom (rx) : ORIGIN = 0x08004000, LENGTH = 100K
27 | ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
28 | }
29 |
30 | /* Include the common ld script. */
31 | INCLUDE libopencm3_stm32f1.ld
32 |
--------------------------------------------------------------------------------
/src/blink/uf2conv.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python
2 | # (c) Microsoft
3 | # License: MIT
4 |
5 | import sys
6 | import struct
7 | import subprocess
8 | import re
9 | import os
10 | import os.path
11 | import argparse
12 |
13 | UF2_MAGIC_START0 = 0x0A324655 # "UF2\n"
14 | UF2_MAGIC_START1 = 0x9E5D5157 # Randomly selected
15 | UF2_MAGIC_END = 0x0AB16F30 # Ditto
16 |
17 | INFO_FILE = "/INFO_UF2.TXT"
18 |
19 | appstartaddr = 0x2000
20 |
21 | def isUF2(buf):
22 | w = struct.unpack(" 476:
48 | assert False, "Invalid UF2 data size at " + ptr
49 | newaddr = hd[3]
50 | if curraddr == None:
51 | appstartaddr = newaddr
52 | curraddr = newaddr
53 | padding = newaddr - curraddr
54 | if padding < 0:
55 | assert False, "Block out of order at " + ptr
56 | if padding > 10*1024*1024:
57 | assert False, "More than 10M of padding needed at " + ptr
58 | if padding % 4 != 0:
59 | assert False, "Non-word padding size at " + ptr
60 | while padding > 0:
61 | padding -= 4
62 | outp += "\x00\x00\x00\x00"
63 | outp += block[32 : 32 + datalen]
64 | curraddr = newaddr + datalen
65 | return outp
66 |
67 | def convertToUF2(fileContent):
68 | datapadding = ""
69 | while len(datapadding) < 512 - 256 - 32 - 4:
70 | datapadding += "\x00\x00\x00\x00"
71 | numblocks = (len(fileContent) + 255) / 256
72 | outp = ""
73 | for blockno in range(0, numblocks):
74 | ptr = 256 * blockno
75 | chunk = fileContent[ptr:ptr + 256]
76 | hd = struct.pack("= 3 and words[1] == "2" and words[2] == "FAT":
152 | drives.append(words[0])
153 | else:
154 | rootpath = "/media"
155 | if sys.platform == "darwin":
156 | rootpath = "/Volumes"
157 | elif sys.platform == "linux":
158 | tmp = rootpath + "/" + os.environ["USER"]
159 | if os.path.isdir(tmp):
160 | rootpath = tmp
161 | for d in os.listdir(rootpath):
162 | drives.append(os.path.join(rootpath, d))
163 |
164 | def hasInfo(d):
165 | try:
166 | return os.path.isfile(d + INFO_FILE)
167 | except:
168 | return False
169 |
170 | return filter(hasInfo, drives)
171 |
172 | def boardID(path):
173 | with open(path + INFO_FILE, mode='r') as file:
174 | fileContent = file.read()
175 | return re.search("Board-ID: ([^\r\n]*)", fileContent).group(1)
176 |
177 | def listdrives():
178 | for d in getdrives():
179 | print d, boardID(d)
180 |
181 | def writeFile(name, buf):
182 | with open(name, "wb") as f:
183 | f.write(buf)
184 | print "Wrote %d bytes to %s." % (len(buf), name)
185 |
186 | def main():
187 | global appstartaddr
188 | def error(msg):
189 | print msg
190 | sys.exit(1)
191 | parser = argparse.ArgumentParser(description='Convert to UF2 or flash directly.')
192 | parser.add_argument('input', metavar='INPUT', type=str, nargs='?',
193 | help='input file (HEX, BIN or UF2)')
194 | parser.add_argument('-b' , '--base', dest='base', type=str,
195 | default="0x2000",
196 | help='set base address of application for BIN format (default: 0x2000)')
197 | parser.add_argument('-o' , '--output', metavar="FILE", dest='output', type=str,
198 | help='write output to named file; defaults to "flash.uf2" or "flash.bin" where sensible')
199 | parser.add_argument('-d' , '--device', dest="device_path",
200 | help='select a device path to flash')
201 | parser.add_argument('-l' , '--list', action='store_true',
202 | help='list connected devices')
203 | parser.add_argument('-c' , '--convert', action='store_true',
204 | help='do not flash, just convert')
205 | args = parser.parse_args()
206 | appstartaddr = int(args.base, 0)
207 | if args.list:
208 | listdrives()
209 | else:
210 | if not args.input:
211 | error("Need input file")
212 | with open(args.input, mode='rb') as file:
213 | inpbuf = file.read()
214 | fromUF2 = isUF2(inpbuf)
215 | ext = "uf2"
216 | if fromUF2:
217 | outbuf = convertFromUF2(inpbuf)
218 | ext = "bin"
219 | elif isHEX(inpbuf):
220 | outbuf = convertFromHexToUF2(inpbuf)
221 | else:
222 | outbuf = convertToUF2(inpbuf)
223 | print "Converting to %s, output size: %d, start address: 0x%x" % (ext, len(outbuf), appstartaddr)
224 |
225 | if args.convert:
226 | drives = []
227 | if args.output == None:
228 | args.output = "flash." + ext
229 | else:
230 | drives = getdrives()
231 |
232 | if args.output:
233 | writeFile(args.output, outbuf)
234 | else:
235 | if len(drives) == 0:
236 | error("No drive to deploy.")
237 | for d in drives:
238 | print "Flashing %s (%s)" % (d, boardID(d))
239 | writeFile(outbuf, d + "/NEW.UF2")
240 |
241 | if __name__ == "__main__":
242 | main()
243 |
--------------------------------------------------------------------------------
/src/bmp.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | d=$(ls -1 /dev/cu.usbmodem* | head -1)
4 | cat <
20 | #include
21 |
22 | #include "uf2.h"
23 | #include "dapboot.h"
24 | #include "target.h"
25 | #include "usb_conf.h"
26 | #include "webusb.h"
27 | #include "winusb.h"
28 | #include "config.h"
29 |
30 | #include
31 |
32 | static inline void __set_MSP(uint32_t topOfMainStack) {
33 | asm("msr msp, %0" : : "r" (topOfMainStack));
34 | }
35 |
36 | bool validate_application(void) {
37 | if ((*(volatile uint32_t *)APP_BASE_ADDRESS & 0x2FFE0000) == 0x20000000) {
38 | return true;
39 | }
40 | return false;
41 | }
42 |
43 | static void jump_to_application(void) __attribute__ ((noreturn));
44 |
45 | static void jump_to_application(void) {
46 | vector_table_t* app_vector_table = (vector_table_t*)APP_BASE_ADDRESS;
47 |
48 | /* Use the application's vector table */
49 | target_relocate_vector_table();
50 |
51 | /* Do any necessary early setup for the application */
52 | target_pre_main();
53 |
54 | /* Initialize the application's stack pointer */
55 | __set_MSP((uint32_t)(app_vector_table->initial_sp_value));
56 |
57 | /* Jump to the application entry point */
58 | app_vector_table->reset();
59 |
60 | while (1);
61 | }
62 |
63 | uint32_t msTimer;
64 | extern int msc_started;
65 |
66 | int main(void) {
67 | bool appValid = validate_application();
68 |
69 | if (appValid && target_get_force_app()) {
70 | jump_to_application();
71 | return 0;
72 | }
73 |
74 | /* Setup clocks */
75 | target_clock_setup();
76 |
77 | /* Initialize GPIO/LEDs if needed */
78 | target_gpio_setup();
79 |
80 | if (target_get_force_bootloader() || !appValid) {
81 | /* Setup USB */
82 | {
83 | char serial[USB_SERIAL_NUM_LENGTH+1];
84 | serial[0] = '\0';
85 | target_get_serial_number(serial, USB_SERIAL_NUM_LENGTH);
86 | usb_set_serial_number(serial);
87 | }
88 |
89 | usbd_device* usbd_dev = usb_setup();
90 | //dfu_setup(usbd_dev, &target_manifest_app, NULL, NULL);
91 | usb_msc_init(usbd_dev, 0x82, 64, 0x01, 64, "Example Ltd", "UF2 Bootloader",
92 | "42.00", UF2_NUM_BLOCKS, read_block, write_block);
93 | winusb_setup(usbd_dev);
94 |
95 | int cycleCount = 0;
96 | int br = 500;
97 | int d = 1;
98 |
99 | while (1) {
100 | cycleCount++;
101 |
102 | target_set_led(cycleCount < br);
103 |
104 | if (cycleCount >= 700) {
105 | msTimer++;
106 | cycleCount = 0;
107 |
108 | br += d;
109 | if (br > 700)
110 | d = -2;
111 | else if (br < 10)
112 | d = 2;
113 |
114 | //int v = msTimer % 500;
115 | //target_set_led(v < 50);
116 |
117 | ghostfat_1ms();
118 |
119 | if (appValid && !msc_started && msTimer > 3000) {
120 | target_manifest_app();
121 | }
122 | }
123 |
124 | usbd_poll(usbd_dev);
125 | }
126 | } else {
127 | jump_to_application();
128 | }
129 |
130 | return 0;
131 | }
132 |
--------------------------------------------------------------------------------
/src/dapboot.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #ifndef DAPBOOT_H_INCLUDED
20 | #define DAPBOOT_H_INCLUDED
21 |
22 | extern bool validate_application(void);
23 |
24 | #endif
25 |
--------------------------------------------------------------------------------
/src/debug.cfg:
--------------------------------------------------------------------------------
1 | gdb_port pipe
2 | gdb_memory_map disable
3 |
4 | $_TARGETNAME configure -event gdb-attach {
5 | echo "Halting target"
6 | halt
7 | }
8 |
9 | $_TARGETNAME configure -event gdb-detach {
10 | echo "Resetting target"
11 | reset
12 | }
--------------------------------------------------------------------------------
/src/dmesg.c:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2017 Lancaster University.
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a
7 | copy of this software and associated documentation files (the "Software"),
8 | to deal in the Software without restriction, including without limitation
9 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 | and/or sell copies of the Software, and to permit persons to whom the
11 | Software is furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 | DEALINGS IN THE SOFTWARE.
23 | */
24 |
25 | #include "dmesg.h"
26 | #include
27 | #include "libopencm3/cm3/cortex.h"
28 |
29 | CodalLogStore codalLogStore;
30 |
31 | static void logwrite(const char *msg);
32 |
33 | static void logwriten(const char *msg, int l)
34 | {
35 | if (codalLogStore.ptr + l >= sizeof(codalLogStore.buffer))
36 | {
37 | const int jump = sizeof(codalLogStore.buffer) / 4;
38 | codalLogStore.ptr -= jump;
39 | memmove(codalLogStore.buffer, codalLogStore.buffer + jump, codalLogStore.ptr);
40 | // zero-out the rest so it looks OK in the debugger
41 | memset(codalLogStore.buffer + codalLogStore.ptr, 0, sizeof(codalLogStore.buffer) - codalLogStore.ptr);
42 | }
43 | if (l + codalLogStore.ptr >= sizeof(codalLogStore.buffer))
44 | {
45 | logwrite("DMESG line too long!\n");
46 | return;
47 | }
48 | memcpy(codalLogStore.buffer + codalLogStore.ptr, msg, l);
49 | codalLogStore.ptr += l;
50 | codalLogStore.buffer[codalLogStore.ptr] = 0;
51 | }
52 |
53 | static void logwrite(const char *msg)
54 | {
55 | logwriten(msg, strlen(msg));
56 | }
57 |
58 | static void writeDecNum(char *buf, int32_t n)
59 | {
60 | if (n < 0) {
61 | *buf++ = '-';
62 | n = -n;
63 | }
64 |
65 | if (n == 0) {
66 | *buf++ = '0';
67 | *buf++ = 0;
68 | return;
69 | }
70 |
71 | char tmp[20];
72 | int i = 0;
73 | while (n > 0) {
74 | tmp[i++] = (n % 10) + '0';
75 | n /= 10;
76 | }
77 |
78 | while (--i > 0) {
79 | *buf++ = tmp[i];
80 | }
81 |
82 | *buf = 0;
83 | }
84 |
85 | static void writeNum(char *buf, uint32_t n, bool full)
86 | {
87 | int i = 0;
88 | int sh = 28;
89 | while (sh >= 0)
90 | {
91 | int d = (n >> sh) & 0xf;
92 | if (full || d || sh == 0 || i)
93 | {
94 | buf[i++] = d > 9 ? 'A' + d - 10 : '0' + d;
95 | }
96 | sh -= 4;
97 | }
98 | buf[i] = 0;
99 | }
100 |
101 | static void logwritenum(uint32_t n, bool full, bool hex)
102 | {
103 | char buff[20];
104 |
105 | if (hex)
106 | {
107 | writeNum(buff, n, full);
108 | logwrite("0x");
109 | }
110 | else
111 | {
112 | writeDecNum(buff, n);
113 | }
114 |
115 | logwrite(buff);
116 | }
117 |
118 | void codal_dmesg(const char *format, ...)
119 | {
120 | va_list arg;
121 | va_start(arg, format);
122 | codal_vdmesg(format, arg);
123 | va_end(arg);
124 | }
125 |
126 | void codal_vdmesg(const char *format, va_list ap)
127 | {
128 | const char *end = format;
129 |
130 | CM_ATOMIC_BLOCK() {
131 |
132 | while (*end)
133 | {
134 | if (*end++ == '%')
135 | {
136 | logwriten(format, end - format - 1);
137 | uint32_t val = va_arg(ap, uint32_t);
138 | switch (*end++)
139 | {
140 | case 'c':
141 | logwriten((const char *)&val, 1);
142 | break;
143 | case 'd':
144 | logwritenum(val, false, false);
145 | break;
146 | case 'x':
147 | logwritenum(val, false, true);
148 | break;
149 | case 'p':
150 | case 'X':
151 | logwritenum(val, true, true);
152 | break;
153 | case 's':
154 | logwrite((char *)(void *)val);
155 | break;
156 | case '%':
157 | logwrite("%");
158 | break;
159 | default:
160 | logwrite("???");
161 | break;
162 | }
163 | format = end;
164 | }
165 | }
166 | logwriten(format, end - format);
167 | logwrite("\n");
168 |
169 | }
170 | }
171 |
--------------------------------------------------------------------------------
/src/dmesg.h:
--------------------------------------------------------------------------------
1 | /*
2 | The MIT License (MIT)
3 |
4 | Copyright (c) 2017 Lancaster University.
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a
7 | copy of this software and associated documentation files (the "Software"),
8 | to deal in the Software without restriction, including without limitation
9 | the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 | and/or sell copies of the Software, and to permit persons to whom the
11 | Software is furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in
14 | all copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 | THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 | DEALINGS IN THE SOFTWARE.
23 | */
24 |
25 | #ifndef CODAL_DMESG_H
26 | #define CODAL_DMESG_H
27 |
28 | #define DEVICE_DMESG_BUFFER_SIZE 1024
29 |
30 | #if DEVICE_DMESG_BUFFER_SIZE > 0
31 |
32 | #include
33 | #include
34 |
35 | #if DEVICE_DMESG_BUFFER_SIZE < 256
36 | #error "Too small DMESG buffer"
37 | #endif
38 |
39 | typedef struct CodalLogStore
40 | {
41 | uint32_t ptr;
42 | char buffer[DEVICE_DMESG_BUFFER_SIZE];
43 | } CodalLogStore;
44 | extern CodalLogStore codalLogStore;
45 |
46 | /**
47 | * Log formatted message to an internal buffer.
48 | *
49 | * Supported format strings:
50 | * %c - single character
51 | * %d - decimal number
52 | * %x - hexadecimal number (with 0x)
53 | * %p - hexadecimal number padded with zeros (and with 0x)
54 | * %X - hexadecimal number padded with zeros (and with 0x)
55 | * %s - '\0'-terminated string
56 | * %% - literal %
57 | * Typically used via the DMESG() macro.
58 | *
59 | * @param format Format string
60 | *
61 | * @code
62 | * uint32_t k;
63 | * void *ptr;
64 | * ...
65 | * DMESG("USB: Error #%d at %X", k, ptr);
66 | * @endcode
67 | */
68 | void codal_dmesg(const char *format, ...);
69 | void codal_vdmesg(const char *format, va_list ap);
70 |
71 | #define DMESG codal_dmesg
72 |
73 | #else
74 |
75 | #define DMESG(...) ((void)0)
76 |
77 | #endif
78 |
79 | #define NOOP(...) do{}while(0)
80 |
81 | #endif
82 |
--------------------------------------------------------------------------------
/src/dummy.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | /* Default dummy implementations for optional target functions */
20 |
21 | #include
22 | #include
23 | #include
24 |
25 | void target_get_serial_number(char* dest, size_t max_chars) __attribute__((weak));
26 | void target_log(const char* str) __attribute__((weak));
27 | void target_manifest_app(void) __attribute__((weak));
28 | void target_pre_main(void) __attribute__((weak));
29 |
30 | void target_get_serial_number(char* dest, size_t max_chars) {
31 | (void)max_chars;
32 | if (dest) {
33 | dest[0] = '\0';
34 | }
35 | }
36 |
37 | void target_log(const char* str) {
38 | (void)str;
39 | }
40 |
41 | void target_manifest_app(void) {
42 | scb_reset_system();
43 | }
44 |
45 | void target_pre_main(void)
46 | {
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/gdb.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | ./bmp.sh > build/debug.gdb
4 | arm-none-eabi-gdb --command=build/debug.gdb
5 |
--------------------------------------------------------------------------------
/src/ghostfat.c:
--------------------------------------------------------------------------------
1 |
2 | #include "uf2.h"
3 |
4 | #include
5 | #include "target.h"
6 | #include "dmesg.h"
7 |
8 | typedef struct {
9 | uint8_t JumpInstruction[3];
10 | uint8_t OEMInfo[8];
11 | uint16_t SectorSize;
12 | uint8_t SectorsPerCluster;
13 | uint16_t ReservedSectors;
14 | uint8_t FATCopies;
15 | uint16_t RootDirectoryEntries;
16 | uint16_t TotalSectors16;
17 | uint8_t MediaDescriptor;
18 | uint16_t SectorsPerFAT;
19 | uint16_t SectorsPerTrack;
20 | uint16_t Heads;
21 | uint32_t HiddenSectors;
22 | uint32_t TotalSectors32;
23 | uint8_t PhysicalDriveNum;
24 | uint8_t Reserved;
25 | uint8_t ExtendedBootSig;
26 | uint32_t VolumeSerialNumber;
27 | uint8_t VolumeLabel[11];
28 | uint8_t FilesystemIdentifier[8];
29 | } __attribute__((packed)) FAT_BootBlock;
30 |
31 | typedef struct {
32 | char name[8];
33 | char ext[3];
34 | uint8_t attrs;
35 | uint8_t reserved;
36 | uint8_t createTimeFine;
37 | uint16_t createTime;
38 | uint16_t createDate;
39 | uint16_t lastAccessDate;
40 | uint16_t highStartCluster;
41 | uint16_t updateTime;
42 | uint16_t updateDate;
43 | uint16_t startCluster;
44 | uint32_t size;
45 | } __attribute__((packed)) DirEntry;
46 |
47 | static size_t flashSize(void) {
48 | return FLASH_SIZE_OVERRIDE;
49 | }
50 |
51 | //#define DBG NOOP
52 | #define DBG DMESG
53 |
54 | struct TextFile {
55 | const char name[11];
56 | const char *content;
57 | };
58 |
59 | #define NUM_FAT_BLOCKS UF2_NUM_BLOCKS
60 |
61 | #define STR0(x) #x
62 | #define STR(x) STR0(x)
63 | const char infoUf2File[] = //
64 | "UF2 Bootloader " UF2_VERSION "\r\n"
65 | "Model: " PRODUCT_NAME "\r\n"
66 | "Board-ID: " BOARD_ID "\r\n";
67 |
68 | const char indexFile[] = //
69 | "\n"
70 | ""
71 | ""
72 | ""
75 | ""
76 | "\n";
77 |
78 | static const struct TextFile info[] = {
79 | {.name = "INFO_UF2TXT", .content = infoUf2File},
80 | {.name = "INDEX HTM", .content = indexFile},
81 | {.name = "CURRENT UF2"},
82 | };
83 | #define NUM_INFO (int)(sizeof(info) / sizeof(info[0]))
84 |
85 | #define UF2_SIZE (flashSize() * 2)
86 | #define UF2_SECTORS (UF2_SIZE / 512)
87 | #define UF2_FIRST_SECTOR (NUM_INFO + 1)
88 | #define UF2_LAST_SECTOR (uint32_t)(UF2_FIRST_SECTOR + UF2_SECTORS - 1)
89 |
90 | #define RESERVED_SECTORS 1
91 | #define ROOT_DIR_SECTORS 4
92 | #define SECTORS_PER_FAT ((NUM_FAT_BLOCKS * 2 + 511) / 512)
93 |
94 | #define START_FAT0 RESERVED_SECTORS
95 | #define START_FAT1 (START_FAT0 + SECTORS_PER_FAT)
96 | #define START_ROOTDIR (START_FAT1 + SECTORS_PER_FAT)
97 | #define START_CLUSTERS (START_ROOTDIR + ROOT_DIR_SECTORS)
98 |
99 | static const FAT_BootBlock BootBlock = {
100 | .JumpInstruction = {0xeb, 0x3c, 0x90},
101 | .OEMInfo = "UF2 UF2 ",
102 | .SectorSize = 512,
103 | .SectorsPerCluster = 1,
104 | .ReservedSectors = RESERVED_SECTORS,
105 | .FATCopies = 2,
106 | .RootDirectoryEntries = (ROOT_DIR_SECTORS * 512 / 32),
107 | .TotalSectors16 = NUM_FAT_BLOCKS - 2,
108 | .MediaDescriptor = 0xF8,
109 | .SectorsPerFAT = SECTORS_PER_FAT,
110 | .SectorsPerTrack = 1,
111 | .Heads = 1,
112 | .ExtendedBootSig = 0x29,
113 | .VolumeSerialNumber = 0x00420042,
114 | .VolumeLabel = VOLUME_LABEL,
115 | .FilesystemIdentifier = "FAT16 ",
116 | };
117 |
118 | #define NO_CACHE 0xffffffff
119 |
120 | static uint32_t flashAddr = NO_CACHE;
121 | static uint8_t flashBuf[FLASH_PAGE_SIZE] __attribute__((aligned(4)));
122 | static bool firstFlush = true;
123 | static bool hadWrite = false;
124 | static uint32_t ms;
125 | static uint32_t resetTime;
126 | static uint32_t lastFlush;
127 |
128 | static void flushFlash(void) {
129 | lastFlush = ms;
130 | if (flashAddr == NO_CACHE)
131 | return;
132 |
133 | if (firstFlush) {
134 | firstFlush = false;
135 |
136 | // disable bootloader or something
137 | }
138 |
139 | DBG("Flush at %x", flashAddr);
140 | if (memcmp(flashBuf, (void *)flashAddr, FLASH_PAGE_SIZE) != 0) {
141 | DBG("Write flush at %x", flashAddr);
142 |
143 | target_flash_unlock();
144 | bool ok = target_flash_program_array((void *)flashAddr, (void*)flashBuf, FLASH_PAGE_SIZE / 2);
145 | target_flash_lock();
146 | (void)ok;
147 | }
148 |
149 | flashAddr = NO_CACHE;
150 | }
151 |
152 | static void flash_write(uint32_t dst, const uint8_t *src, int len) {
153 | uint32_t newAddr = dst & ~(FLASH_PAGE_SIZE - 1);
154 |
155 | hadWrite = true;
156 |
157 | if (newAddr != flashAddr) {
158 | flushFlash();
159 | flashAddr = newAddr;
160 | memcpy(flashBuf, (void *)newAddr, FLASH_PAGE_SIZE);
161 | }
162 | memcpy(flashBuf + (dst & (FLASH_PAGE_SIZE - 1)), src, len);
163 | }
164 |
165 | static void uf2_timer_start(int delay) {
166 | resetTime = ms + delay;
167 | }
168 |
169 | // called roughly every 1ms
170 | void ghostfat_1ms() {
171 | ms++;
172 |
173 | if (resetTime && ms >= resetTime) {
174 | flushFlash();
175 | target_manifest_app();
176 | while (1);
177 | }
178 |
179 | if (lastFlush && ms - lastFlush > 100) {
180 | flushFlash();
181 | }
182 | }
183 |
184 | static void padded_memcpy(char *dst, const char *src, int len) {
185 | for (int i = 0; i < len; ++i) {
186 | if (*src)
187 | *dst = *src++;
188 | else
189 | *dst = ' ';
190 | dst++;
191 | }
192 | }
193 |
194 | int read_block(uint32_t block_no, uint8_t *data) {
195 | memset(data, 0, 512);
196 | uint32_t sectionIdx = block_no;
197 |
198 | if (block_no == 0) {
199 | memcpy(data, &BootBlock, sizeof(BootBlock));
200 | data[510] = 0x55;
201 | data[511] = 0xaa;
202 | // logval("data[0]", data[0]);
203 | } else if (block_no < START_ROOTDIR) {
204 | sectionIdx -= START_FAT0;
205 | // logval("sidx", sectionIdx);
206 | if (sectionIdx >= SECTORS_PER_FAT)
207 | sectionIdx -= SECTORS_PER_FAT;
208 | if (sectionIdx == 0) {
209 | data[0] = 0xf0;
210 | for (int i = 1; i < NUM_INFO * 2 + 4; ++i) {
211 | data[i] = 0xff;
212 | }
213 | }
214 | for (int i = 0; i < 256; ++i) {
215 | uint32_t v = sectionIdx * 256 + i;
216 | if (UF2_FIRST_SECTOR <= v && v <= UF2_LAST_SECTOR)
217 | ((uint16_t *)(void *)data)[i] = v == UF2_LAST_SECTOR ? 0xffff : v + 1;
218 | }
219 | } else if (block_no < START_CLUSTERS) {
220 | sectionIdx -= START_ROOTDIR;
221 | if (sectionIdx == 0) {
222 | DirEntry *d = (void *)data;
223 | padded_memcpy(d->name, (const char *)BootBlock.VolumeLabel, 11);
224 | d->attrs = 0x28;
225 | for (int i = 0; i < NUM_INFO; ++i) {
226 | d++;
227 | const struct TextFile *inf = &info[i];
228 | d->size = inf->content ? strlen(inf->content) : UF2_SIZE;
229 | d->startCluster = i + 2;
230 | padded_memcpy(d->name, inf->name, 11);
231 | }
232 | }
233 | } else {
234 | sectionIdx -= START_CLUSTERS;
235 | if (sectionIdx < NUM_INFO - 1) {
236 | memcpy(data, info[sectionIdx].content, strlen(info[sectionIdx].content));
237 | } else {
238 | sectionIdx -= NUM_INFO - 1;
239 | uint32_t addr = sectionIdx * 256;
240 | if (addr < flashSize()) {
241 | UF2_Block *bl = (void *)data;
242 | bl->magicStart0 = UF2_MAGIC_START0;
243 | bl->magicStart1 = UF2_MAGIC_START1;
244 | bl->magicEnd = UF2_MAGIC_END;
245 | bl->blockNo = sectionIdx;
246 | bl->numBlocks = flashSize() / 256;
247 | bl->targetAddr = addr | 0x8000000;
248 | bl->payloadSize = 256;
249 | memcpy(bl->data, (void *)addr, bl->payloadSize);
250 | }
251 | }
252 | }
253 |
254 | return 0;
255 | }
256 |
257 | static void write_block_core(uint32_t block_no, const uint8_t *data, bool quiet, WriteState *state) {
258 | const UF2_Block *bl = (const void *)data;
259 |
260 | (void)block_no;
261 |
262 | // DBG("Write magic: %x", bl->magicStart0);
263 |
264 | if (!is_uf2_block(bl) || !UF2_IS_MY_FAMILY(bl)) {
265 | return;
266 | }
267 |
268 | if ((bl->flags & UF2_FLAG_NOFLASH) || bl->payloadSize > 256 || (bl->targetAddr & 0xff) ||
269 | bl->targetAddr < USER_FLASH_START || bl->targetAddr + bl->payloadSize > USER_FLASH_END) {
270 | DBG("Skip block at %x", bl->targetAddr);
271 | // this happens when we're trying to re-flash CURRENT.UF2 file previously
272 | // copied from a device; we still want to count these blocks to reset properly
273 | } else {
274 | // logval("write block at", bl->targetAddr);
275 | DBG("Write block at %x", bl->targetAddr);
276 | flash_write(bl->targetAddr, bl->data, bl->payloadSize);
277 | }
278 |
279 | bool isSet = false;
280 |
281 | if (state && bl->numBlocks) {
282 | if (state->numBlocks != bl->numBlocks) {
283 | if (bl->numBlocks >= MAX_BLOCKS || state->numBlocks)
284 | state->numBlocks = 0xffffffff;
285 | else
286 | state->numBlocks = bl->numBlocks;
287 | }
288 | if (bl->blockNo < MAX_BLOCKS) {
289 | uint8_t mask = 1 << (bl->blockNo % 8);
290 | uint32_t pos = bl->blockNo / 8;
291 | if (!(state->writtenMask[pos] & mask)) {
292 | // logval("incr", state->numWritten);
293 | state->writtenMask[pos] |= mask;
294 | state->numWritten++;
295 | }
296 | if (state->numWritten >= state->numBlocks) {
297 | // wait a little bit before resetting, to avoid Windows transmit error
298 | // https://github.com/Microsoft/uf2-samd21/issues/11
299 | if (!quiet) {
300 | uf2_timer_start(30);
301 | isSet = true;
302 | }
303 | }
304 | }
305 | //DBG("wr %d=%d (of %d)", state->numWritten, bl->blockNo, bl->numBlocks);
306 | }
307 |
308 | if (!isSet && !quiet) {
309 | uf2_timer_start(500);
310 | }
311 | }
312 |
313 |
314 | WriteState wrState;
315 |
316 | int write_block(uint32_t lba, const uint8_t *copy_from)
317 | {
318 | target_set_led((wrState.numWritten * 17) & 1);
319 | write_block_core(lba, copy_from, false, &wrState);
320 | target_set_led(0);
321 | return 0;
322 | }
323 |
--------------------------------------------------------------------------------
/src/rules.mk:
--------------------------------------------------------------------------------
1 | ##
2 | ## This file is derived from the libopencm3 project.
3 | ##
4 | ## Copyright (C) 2009 Uwe Hermann
5 | ## Copyright (C) 2010 Piotr Esden-Tempski
6 | ## Copyright (C) 2013 Frantisek Burian
7 | ## Copyright (C) 2016 Devan Lai
8 | ##
9 | ## This library is free software: you can redistribute it and/or modify
10 | ## it under the terms of the GNU Lesser General Public License as published by
11 | ## the Free Software Foundation, either version 3 of the License, or
12 | ## (at your option) any later version.
13 | ##
14 | ## This library is distributed in the hope that it will be useful,
15 | ## but WITHOUT ANY WARRANTY; without even the implied warranty of
16 | ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 | ## GNU Lesser General Public License for more details.
18 | ##
19 | ## You should have received a copy of the GNU Lesser General Public License
20 | ## along with this library. If not, see .
21 | ##
22 |
23 | # Be silent per default, but 'make V=1' will show all compiler calls.
24 | ifneq ($(V),1)
25 | Q := @
26 | NULL := 2>/dev/null
27 | endif
28 |
29 | ####################################################################
30 | # Target Architecture flags
31 | ifeq ($(ARCH),STM32F0)
32 | LIBNAME = opencm3_stm32f0
33 | DEFS += -DSTM32F0
34 | FP_FLAGS ?= -msoft-float
35 | ARCH_FLAGS = -mthumb -mcpu=cortex-m0 $(FP_FLAGS)
36 | OOCD_BOARD ?= target/stm32f0x.cfg
37 | endif
38 | ifeq ($(ARCH),STM32F1)
39 | LIBNAME = opencm3_stm32f1
40 | DEFS += -DSTM32F1
41 | FP_FLAGS ?= -msoft-float
42 | ARCH_FLAGS = -mthumb -mcpu=cortex-m3 $(FP_FLAGS) -mfix-cortex-m3-ldrd
43 | OOCD_BOARD ?= target/stm32f1x.cfg
44 | endif
45 |
46 | LIBNAME ?= opencm3_stm32f0
47 | DEFS ?= -DSTM32F0
48 | FP_FLAGS ?= -msoft-float
49 | ARCH_FLAGS ?= -mthumb -mcpu=cortex-m0 $(FP_FLAGS)
50 |
51 | ####################################################################
52 | # Semihosting support
53 | SEMIHOSTING ?= 0
54 |
55 | ifeq ($(SEMIHOSTING),1)
56 | LDFLAGS += --specs=rdimon.specs
57 | LDLIBS += -lrdimon
58 | DEFS += -DSEMIHOSTING=1
59 | else
60 | DEFS += -DSEMIHOSTING=0
61 | endif
62 |
63 | ####################################################################
64 | # OpenOCD specific variables
65 |
66 | OOCD ?= openocd
67 | OOCD_INTERFACE ?= interface/stlink-v2.cfg
68 | OOCD_BOARD ?= target/stm32f1x.cfg
69 |
70 | ####################################################################
71 | # Executables
72 |
73 | PREFIX ?= arm-none-eabi
74 |
75 | CC := $(PREFIX)-gcc
76 | CXX := $(PREFIX)-g++
77 | LD := $(PREFIX)-gcc
78 | AR := $(PREFIX)-ar
79 | AS := $(PREFIX)-as
80 | OBJCOPY := $(PREFIX)-objcopy
81 | OBJDUMP := $(PREFIX)-objdump
82 | GDB := $(PREFIX)-gdb
83 | STFLASH = $(shell which st-flash)
84 |
85 | ####################################################################
86 | # Source files
87 |
88 | INCLUDE_DIR = $(OPENCM3_DIR)/include
89 | LIB_DIR = $(OPENCM3_DIR)/lib
90 |
91 | ####################################################################
92 | # C flags
93 |
94 | CFLAGS += -Os -g -std=gnu11
95 | CFLAGS += -Wextra -Wshadow -Wimplicit-function-declaration
96 | CFLAGS += -Wredundant-decls -Wmissing-prototypes -Wstrict-prototypes
97 | CFLAGS += -fno-common -ffunction-sections -fdata-sections
98 |
99 | ####################################################################
100 | # C++ flags
101 |
102 | CXXFLAGS += -Os -g
103 | CXXFLAGS += -Wextra -Wshadow -Wredundant-decls -Weffc++
104 | CXXFLAGS += -fno-common -ffunction-sections -fdata-sections
105 |
106 | ####################################################################
107 | # C & C++ preprocessor common flags
108 |
109 | CPPFLAGS += -MD
110 | CPPFLAGS += -Wall -Wundef
111 | CPPFLAGS += -I$(INCLUDE_DIR) $(DEFS)
112 |
113 | ####################################################################
114 | # Linker flags
115 |
116 | LDFLAGS += --static -nostartfiles
117 | LDFLAGS += -L$(LIB_DIR)
118 | LDFLAGS += -T$(LDSCRIPT)
119 | LDFLAGS += -Wl,-Map=$(*).map
120 | LDFLAGS += -Wl,--gc-sections
121 | ifeq ($(V),99)
122 | LDFLAGS += -Wl,--print-gc-sections
123 | endif
124 |
125 | ####################################################################
126 | # Used libraries
127 |
128 | LDLIBS += -l$(LIBNAME)
129 | LDLIBS += -Wl,--start-group -lc -lgcc -lnosys -Wl,--end-group
130 |
131 | ####################################################################
132 | ####################################################################
133 | ####################################################################
134 |
135 | .SUFFIXES: .elf .bin .hex .srec .list .map .images
136 | .SECONDEXPANSION:
137 | .SECONDARY:
138 |
139 | elf: $(BINARY).elf
140 | bin: $(BINARY).bin
141 | hex: $(BINARY).hex
142 | srec: $(BINARY).srec
143 | list: $(BINARY).list
144 |
145 | images: $(BUILD)/$(BINARY).images
146 | ocd-flash: $(BUILD)/$(BINARY).flash
147 |
148 | $(LDSCRIPT):
149 | ifeq (,$(wildcard $(LDSCRIPT)))
150 | $(error Unable to find specified linker script: $(LDSCRIPT))
151 | endif
152 |
153 | $(OPENCM3_DIR)/Makefile:
154 | $(Q)git submodule update --init $(OPENCM3_DIR)
155 |
156 | $(LIB_DIR)/lib$(LIBNAME).a: $(OPENCM3_DIR)/Makefile
157 | $(Q)$(MAKE) -C $(OPENCM3_DIR)
158 |
159 | locm3: $(LIB_DIR)/lib$(LIBNAME).a
160 |
161 | %.images: %.bin %.hex %.srec %.list %.map
162 | @#printf "*** $* images generated ***\n"
163 |
164 | %.bin: %.elf
165 | @#printf " OBJCOPY $(*).bin\n"
166 | $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).tmpbin
167 | $(Q)(cat $(*).tmpbin; cat /dev/zero) | head -c 16384 > $(*).bin
168 |
169 | %.hex: %.elf
170 | @#printf " OBJCOPY $(*).hex\n"
171 | $(Q)$(OBJCOPY) -Oihex $(*).elf $(*).hex
172 |
173 | %.srec: %.elf
174 | @#printf " OBJCOPY $(*).srec\n"
175 | $(Q)$(OBJCOPY) -Osrec $(*).elf $(*).srec
176 |
177 | %.list: %.elf
178 | @#printf " OBJDUMP $(*).list\n"
179 | $(Q)$(OBJDUMP) -S $(*).elf > $(*).list
180 |
181 | %.elf %.map: $(OBJS) $(LDSCRIPT) $(LIB_DIR)/lib$(LIBNAME).a
182 | @#printf " LD $(*).elf\n"
183 | $(Q)$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJS) $(LDLIBS) -o $(*).elf
184 |
185 | $(BUILD)/%.o: %.c $(LIB_DIR)/lib$(LIBNAME).a
186 | @printf " CC $(*).c\n"
187 | $(Q)$(CC) $(CFLAGS) $(CPPFLAGS) $(ARCH_FLAGS) $(VER_FLAGS) -o $@ -c $(*).c
188 |
189 | clean::
190 | @#printf " CLEAN\n"
191 | $(Q)$(RM) *.o *.d *.elf *.bin *.hex *.srec *.list *.map
192 |
193 | %.stlink-flash: %.bin
194 | @printf " FLASH $<\n"
195 | $(Q)$(STFLASH) write $(*).bin 0x08000000
196 |
197 | %.flash: %.elf
198 | @printf " FLASH $<\n"
199 | $(Q)$(OOCD) -f $(OOCD_INTERFACE) \
200 | -f $(OOCD_BOARD) \
201 | -c "program $(*).elf verify reset exit" \
202 | $(NULL)
203 |
204 | .PHONY: images clean elf bin hex srec list locm3
205 |
206 | -include $(OBJS:.o=.d)
207 |
--------------------------------------------------------------------------------
/src/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | set -e
4 | make
5 | (./bmp.sh && echo load && echo quit) > build/flash.gdb
6 | arm-none-eabi-gdb --command=build/flash.gdb
7 |
--------------------------------------------------------------------------------
/src/stm32f103/backup.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | #include "backup.h"
24 |
25 | #define RTC_BKP_DR(reg) MMIO16(BACKUP_REGS_BASE + 4 + (4 * (reg)))
26 |
27 | void backup_write(enum BackupRegister reg, uint32_t value) {
28 | /*
29 | rcc_periph_clock_enable(RCC_PWR);
30 | rcc_periph_clock_enable(RCC_BKP);
31 |
32 | pwr_disable_backup_domain_write_protect();
33 | RTC_BKP_DR((int)reg*2) = value & 0xFFFFUL;
34 | RTC_BKP_DR((int)reg*2+1) = (value & 0xFFFF0000UL) >> 16;
35 | pwr_enable_backup_domain_write_protect();
36 | */
37 | (void)reg;
38 | *(volatile uint32_t*)0x20004000 = value;
39 | }
40 |
41 | uint32_t backup_read(enum BackupRegister reg) {
42 | (void)reg;
43 | return *(volatile uint32_t*)0x20004000;
44 | /*
45 | uint32_t value = ((uint32_t)RTC_BKP_DR((int)reg*2+1) << 16)
46 | | ((uint32_t)RTC_BKP_DR((int)reg*2) << 0);
47 | return value;
48 | */
49 | }
50 |
--------------------------------------------------------------------------------
/src/stm32f103/backup.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #ifndef BACKUP_H_INCLUDED
20 | #define BACKUP_H_INCLUDED
21 |
22 | enum BackupRegister {
23 | BKP0 = 0,
24 | BKP1,
25 | BKP2,
26 | BKP3,
27 | BKP4,
28 | };
29 |
30 | extern void backup_write(enum BackupRegister reg, uint32_t value);
31 | extern uint32_t backup_read(enum BackupRegister reg);
32 |
33 | #endif
34 |
--------------------------------------------------------------------------------
/src/stm32f103/bluepill/config.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #ifndef CONFIG_H_INCLUDED
20 | #define CONFIG_H_INCLUDED
21 |
22 | #define APP_BASE_ADDRESS 0x08004000
23 | #define FLASH_SIZE_OVERRIDE 0x20000
24 | #define FLASH_PAGE_SIZE 1024
25 | #define DFU_UPLOAD_AVAILABLE 1
26 | #define DFU_DOWNLOAD_AVAILABLE 1
27 |
28 | #ifndef HAVE_LED
29 | #define HAVE_LED 0
30 | #endif
31 |
32 | #ifndef HAVE_BUTTON
33 | #define HAVE_BUTTON 0
34 | #endif
35 |
36 | #ifndef HAVE_USB_PULLUP_CONTROL
37 | #define HAVE_USB_PULLUP_CONTROL 0
38 | #endif
39 |
40 | #define UF2_FAMILY 0x5ee21072
41 |
42 | #undef VOLUME_LABEL
43 | #define VOLUME_LABEL "BLUEPILL"
44 | #undef PRODUCT_NAME
45 | #define PRODUCT_NAME "Blue Pill STM32F103xB"
46 | #undef BOARD_ID
47 | #define BOARD_ID "STM32F103-blue-pill-v0"
48 |
49 | //#define DOUBLE_TAP
50 |
51 | #endif
52 |
--------------------------------------------------------------------------------
/src/stm32f103/generic/config.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #ifndef CONFIG_H_INCLUDED
20 | #define CONFIG_H_INCLUDED
21 |
22 | #define APP_BASE_ADDRESS 0x08004000
23 | #define FLASH_SIZE_OVERRIDE 0x20000
24 | #define FLASH_PAGE_SIZE 1024
25 | #define DFU_UPLOAD_AVAILABLE 1
26 | #define DFU_DOWNLOAD_AVAILABLE 1
27 |
28 | #ifndef HAVE_LED
29 | #define HAVE_LED 0
30 | #endif
31 |
32 | #ifndef HAVE_BUTTON
33 | #define HAVE_BUTTON 0
34 | #endif
35 |
36 | #ifndef HAVE_USB_PULLUP_CONTROL
37 | #define HAVE_USB_PULLUP_CONTROL 0
38 | #endif
39 |
40 | #define UF2_FAMILY 0x5ee21072
41 |
42 | #endif
43 |
--------------------------------------------------------------------------------
/src/stm32f103/jacdac/config.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #ifndef CONFIG_H_INCLUDED
20 | #define CONFIG_H_INCLUDED
21 |
22 | #define APP_BASE_ADDRESS 0x08004000
23 | #define FLASH_SIZE_OVERRIDE 0x20000
24 | #define FLASH_PAGE_SIZE 1024
25 | #define DFU_UPLOAD_AVAILABLE 1
26 | #define DFU_DOWNLOAD_AVAILABLE 1
27 |
28 | #define HAVE_LED 1
29 | #define HAVE_BUTTON 0
30 |
31 | #ifndef HAVE_USB_PULLUP_CONTROL
32 | #define HAVE_USB_PULLUP_CONTROL 0
33 | #endif
34 |
35 | #define UF2_FAMILY 0x5ee21072
36 |
37 | #undef VOLUME_LABEL
38 | #define VOLUME_LABEL "JACDAC"
39 | #undef PRODUCT_NAME
40 | #define PRODUCT_NAME "JACDAC Feather STM32F103CB"
41 | #undef BOARD_ID
42 | #define BOARD_ID "STM32F103-jacdac-feather-v0"
43 |
44 | #define CRYSTAL_16MHZ 1
45 |
46 | #endif
47 |
--------------------------------------------------------------------------------
/src/stm32f103/maplemini/config.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #ifndef CONFIG_H_INCLUDED
20 | #define CONFIG_H_INCLUDED
21 |
22 | #define APP_BASE_ADDRESS 0x08004000
23 | #define FLASH_PAGE_SIZE 1024
24 | #define DFU_UPLOAD_AVAILABLE 1
25 | #define DFU_DOWNLOAD_AVAILABLE 1
26 |
27 | #define HAVE_LED 1
28 | #define LED_GPIO_PORT GPIOB
29 | #define LED_GPIO_PIN GPIO1
30 | #define LED_OPEN_DRAIN 0
31 |
32 | /* Technically, there is a button on PB8, but the button is
33 | also shorted to BOOT0, so it's not very useful for us to
34 | sample PB8 on boot, since pulling it high will already
35 | trigger the ROM serial bootloader and prevent us from
36 | running anyways. */
37 | #define HAVE_BUTTON 0
38 |
39 | #define HAVE_USB_PULLUP_CONTROL 1
40 | #define USB_PULLUP_GPIO_PORT GPIOB
41 | #define USB_PULLUP_GPIO_PIN GPIO9
42 | #define USB_PULLUP_ACTIVE_HIGH 0
43 | #define USB_PULLUP_OPEN_DRAIN 1
44 |
45 | #define USES_GPIOA 0
46 | #define USES_GPIOB 1
47 | #define USES_GPIOC 0
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/src/stm32f103/pxt32/config.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #ifndef CONFIG_H_INCLUDED
20 | #define CONFIG_H_INCLUDED
21 |
22 | #define APP_BASE_ADDRESS 0x08004000
23 | #define FLASH_SIZE_OVERRIDE (512*1024)
24 | #define FLASH_PAGE_SIZE 2048
25 | #define DFU_UPLOAD_AVAILABLE 1
26 | #define DFU_DOWNLOAD_AVAILABLE 1
27 |
28 | #ifndef HAVE_LED
29 | #define HAVE_LED 0
30 | #endif
31 |
32 | #ifndef HAVE_BUTTON
33 | #define HAVE_BUTTON 0
34 | #endif
35 |
36 | #ifndef HAVE_USB_PULLUP_CONTROL
37 | #define HAVE_USB_PULLUP_CONTROL 0
38 | #endif
39 |
40 | #define UF2_FAMILY 0x5ee21072
41 |
42 | #endif
43 |
--------------------------------------------------------------------------------
/src/stm32f103/stlink/config.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #ifndef CONFIG_H_INCLUDED
20 | #define CONFIG_H_INCLUDED
21 |
22 | #define APP_BASE_ADDRESS 0x08004000
23 | #define FLASH_SIZE_OVERRIDE 0x20000
24 | #define FLASH_PAGE_SIZE 1024
25 | #define DFU_UPLOAD_AVAILABLE 1
26 | #define DFU_DOWNLOAD_AVAILABLE 1
27 |
28 | #define HAVE_LED 1
29 | #define LED_GPIO_PORT GPIOA
30 | #define LED_GPIO_PIN GPIO9
31 | #define LED_OPEN_DRAIN 0
32 |
33 | #define HAVE_BUTTON 0
34 |
35 | #define HAVE_USB_PULLUP_CONTROL 0
36 |
37 | #define USES_GPIOA 1
38 |
39 | #endif
40 |
--------------------------------------------------------------------------------
/src/stm32f103/stm32f103x8.ld:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the libopencm3 project.
3 | *
4 | * Copyright (C) 2015 Karl Palsson
5 | *
6 | * This library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU Lesser General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU Lesser General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU Lesser General Public License
17 | * along with this library. If not, see .
18 | */
19 |
20 | /* Linker script for STM32F103x8, 64k flash, 20k RAM. */
21 |
22 | /* Define memory regions. */
23 | /* 8k for the bootloader */
24 | MEMORY
25 | {
26 | rom (rx) : ORIGIN = 0x08000000, LENGTH = 16K
27 | ram (rwx) : ORIGIN = 0x20000000, LENGTH = 20K
28 | }
29 |
30 | /* Include the common ld script. */
31 | INCLUDE libopencm3_stm32f1.ld
32 |
--------------------------------------------------------------------------------
/src/stm32f103/target_stm32f103.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | /* Common STM32F103 target functions */
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 |
28 | #include "target.h"
29 | #include "config.h"
30 | #include "backup.h"
31 |
32 | #ifndef USES_GPIOA
33 | #if (HAVE_USB_PULLUP_CONTROL == 0)
34 | #define USES_GPIOA 1
35 | #else
36 | #define USES_GPIOA 0
37 | #endif
38 | #endif
39 |
40 | #ifndef USES_GPIOB
41 | #define USES_GPIOB 0
42 | #endif
43 |
44 | #ifndef USES_GPIOC
45 | #define USES_GPIOC 0
46 | #endif
47 |
48 | #ifdef FLASH_SIZE_OVERRIDE
49 | _Static_assert((FLASH_BASE + FLASH_SIZE_OVERRIDE >= APP_BASE_ADDRESS),
50 | "Incompatible flash size");
51 | #endif
52 |
53 | static const uint32_t CMD_BOOT = 0x544F4F42UL;
54 | static const uint32_t CMD_APP = 0x3f82722aUL;
55 |
56 | //#define USE_HSI 1
57 |
58 | void target_clock_setup(void) {
59 | #ifdef USE_HSI
60 | /* Set the system clock to 48MHz from the internal RC oscillator.
61 | The clock tolerance doesn't meet the official USB spec, but
62 | it's better than nothing. */
63 | rcc_clock_setup_in_hsi_out_48mhz();
64 | #else
65 | /* Set system clock to 72 MHz from an external crystal */
66 | #ifdef CRYSTAL_16MHZ
67 | rcc_clock_setup_in_hse_16mhz_out_72mhz();
68 | #else
69 | rcc_clock_setup_in_hse_8mhz_out_72mhz();
70 | #endif
71 | #endif
72 | }
73 |
74 | void target_set_led(int on) {
75 | #if HAVE_LED
76 | if ((on && LED_OPEN_DRAIN) || (!on && !LED_OPEN_DRAIN)) {
77 | gpio_clear(LED_GPIO_PORT, LED_GPIO_PIN);
78 | } else {
79 | gpio_set(LED_GPIO_PORT, LED_GPIO_PIN);
80 | }
81 | #else
82 | (void)on;
83 | #endif
84 | }
85 |
86 | static void sleep_us(int us){
87 | for (int i = 0; i < us*10; i++) {
88 | __asm__("nop");
89 | }
90 | }
91 |
92 | void target_gpio_setup(void) {
93 | /* Enable GPIO clocks */
94 | rcc_periph_clock_enable(RCC_GPIOA);
95 | rcc_periph_clock_enable(RCC_GPIOB);
96 | rcc_periph_clock_enable(RCC_GPIOC);
97 |
98 | /* Setup LEDs */
99 | #if HAVE_LED
100 | {
101 | const uint8_t mode = GPIO_MODE_OUTPUT_10_MHZ;
102 | const uint8_t conf = (LED_OPEN_DRAIN ? GPIO_CNF_OUTPUT_OPENDRAIN
103 | : GPIO_CNF_OUTPUT_PUSHPULL);
104 | if (LED_OPEN_DRAIN) {
105 | gpio_set(LED_GPIO_PORT, LED_GPIO_PIN);
106 | } else {
107 | gpio_clear(LED_GPIO_PORT, LED_GPIO_PIN);
108 | }
109 | gpio_set_mode(LED_GPIO_PORT, mode, conf, LED_GPIO_PIN);
110 | }
111 | #endif
112 |
113 | /* Setup the internal pull-up/pull-down for the button */
114 | #if HAVE_BUTTON
115 | {
116 | const uint8_t mode = GPIO_MODE_INPUT;
117 | const uint8_t conf = GPIO_CNF_INPUT_PULL_UPDOWN;
118 | gpio_set_mode(BUTTON_GPIO_PORT, mode, conf, BUTTON_GPIO_PIN);
119 | if (BUTTON_ACTIVE_HIGH) {
120 | gpio_clear(BUTTON_GPIO_PORT, BUTTON_GPIO_PIN);
121 | } else {
122 | gpio_set(BUTTON_GPIO_PORT, BUTTON_GPIO_PIN);
123 | }
124 | }
125 | #endif
126 |
127 | #if HAVE_USB_PULLUP_CONTROL
128 | {
129 | const uint8_t mode = GPIO_MODE_OUTPUT_10_MHZ;
130 | const uint8_t conf = (USB_PULLUP_OPEN_DRAIN ? GPIO_CNF_OUTPUT_OPENDRAIN
131 | : GPIO_CNF_OUTPUT_PUSHPULL);
132 | /* Configure USB pullup transistor, initially disabled */
133 | if (USB_PULLUP_ACTIVE_HIGH) {
134 | gpio_clear(USB_PULLUP_GPIO_PORT, USB_PULLUP_GPIO_PIN);
135 | } else {
136 | gpio_set(USB_PULLUP_GPIO_PORT, USB_PULLUP_GPIO_PIN);
137 | }
138 | gpio_set_mode(USB_PULLUP_GPIO_PORT, mode, conf, USB_PULLUP_GPIO_PIN);
139 | }
140 | #else
141 | {
142 | /* Drive the USB DP pin to override the pull-up */
143 | gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_10_MHZ,
144 | GPIO_CNF_OUTPUT_PUSHPULL, GPIO12);
145 | }
146 | #endif
147 |
148 | #if 0
149 | while(1) {
150 | target_set_led(1);
151 | sleep_us(1200000);
152 | target_set_led(0);
153 | sleep_us(1200000);
154 | }
155 |
156 | // TFT
157 | // RST
158 | gpio_clear(GPIOC, (1 << 4));
159 | sleep_us(20000);
160 | //gpio_set(GPIOC, (1 << 4));
161 | sleep_us(20000);
162 | #endif
163 | }
164 |
165 | const usbd_driver* target_usb_init(void) {
166 | rcc_periph_reset_pulse(RST_USB);
167 |
168 | #if HAVE_USB_PULLUP_CONTROL
169 | /* Enable USB pullup to connect */
170 | if (USB_PULLUP_ACTIVE_HIGH) {
171 | gpio_set(USB_PULLUP_GPIO_PORT, USB_PULLUP_GPIO_PIN);
172 | } else {
173 | gpio_clear(USB_PULLUP_GPIO_PORT, USB_PULLUP_GPIO_PIN);
174 | }
175 | #else
176 | /* Override hard-wired USB pullup to disconnect and reconnect */
177 | gpio_clear(GPIOA, GPIO12);
178 | int i;
179 | for (i = 0; i < 800000; i++) {
180 | __asm__("nop");
181 | }
182 | #endif
183 |
184 | return &st_usbfs_v1_usb_driver;
185 | }
186 |
187 | void target_manifest_app(void) {
188 | backup_write(BKP0, CMD_APP);
189 | scb_reset_system();
190 | }
191 |
192 | bool target_get_force_app(void) {
193 | if (backup_read(BKP0) == CMD_APP) {
194 | backup_write(BKP0, 0);
195 | return true;
196 | }
197 | return false;
198 | }
199 |
200 | bool target_get_force_bootloader(void) {
201 | /* Enable GPIO clocks */
202 | rcc_periph_clock_enable(RCC_GPIOA);
203 | rcc_periph_clock_enable(RCC_GPIOB);
204 | rcc_periph_clock_enable(RCC_GPIOC);
205 |
206 | bool force = true;
207 | /* Check the RTC backup register */
208 | uint32_t cmd = backup_read(BKP0);
209 | if (cmd == CMD_BOOT) {
210 | // asked to go into bootloader?
211 | backup_write(BKP0, 0);
212 | return true;
213 | }
214 | if (cmd == CMD_APP) {
215 | // we were told to reset into app
216 | backup_write(BKP0, 0);
217 | return false;
218 | }
219 |
220 | #ifdef DOUBLE_TAP
221 | target_set_led(1);
222 | // wait for second press on reset
223 | backup_write(BKP0, CMD_BOOT);
224 | for (int i = 0; i < 3500000; ++i)
225 | asm("nop");
226 | backup_write(BKP0, 0);
227 | target_set_led(0);
228 | force = false;
229 | #else
230 | // a reset now should go into app
231 | backup_write(BKP0, CMD_APP);
232 | #endif
233 |
234 | #if HAVE_BUTTON
235 | /* Check if the user button is held down */
236 | if (BUTTON_ACTIVE_HIGH) {
237 | if (gpio_get(BUTTON_GPIO_PORT, BUTTON_GPIO_PIN)) {
238 | force = true;
239 | }
240 | } else {
241 | if (!gpio_get(BUTTON_GPIO_PORT, BUTTON_GPIO_PIN)) {
242 | force = true;
243 | }
244 | }
245 | #endif
246 |
247 | return force;
248 | }
249 |
250 | void target_get_serial_number(char* dest, size_t max_chars) {
251 | desig_get_unique_id_as_string(dest, max_chars+1);
252 | }
253 |
254 | static uint16_t* get_flash_end(void) {
255 | #ifdef FLASH_SIZE_OVERRIDE
256 | /* Allow access to the unofficial full 128KiB flash size */
257 | return (uint16_t*)(FLASH_BASE + FLASH_SIZE_OVERRIDE);
258 | #else
259 | /* Only allow access to the chip's self-reported flash size */
260 | return (uint16_t*)(FLASH_BASE + (size_t)DESIG_FLASH_SIZE*FLASH_PAGE_SIZE);
261 | #endif
262 | }
263 |
264 | size_t target_get_max_firmware_size(void) {
265 | uint8_t* flash_end = (uint8_t*)get_flash_end();
266 | uint8_t* flash_start = (uint8_t*)(APP_BASE_ADDRESS);
267 |
268 | return (flash_end >= flash_start) ? (size_t)(flash_end - flash_start) : 0;
269 | }
270 |
271 | void target_relocate_vector_table(void) {
272 | SCB_VTOR = APP_BASE_ADDRESS & 0xFFFF;
273 | }
274 |
275 | void target_flash_unlock(void) {
276 | flash_unlock();
277 | }
278 |
279 | void target_flash_lock(void) {
280 | flash_lock();
281 | }
282 |
283 | static inline uint16_t* get_flash_page_address(uint16_t* dest) {
284 | return (uint16_t*)(((uint32_t)dest / FLASH_PAGE_SIZE) * FLASH_PAGE_SIZE);
285 | }
286 |
287 | bool target_flash_program_array(uint16_t* dest, const uint16_t* data, size_t half_word_count) {
288 | bool verified = true;
289 |
290 | /* Remember the bounds of erased data in the current page */
291 | static uint16_t* erase_start;
292 | static uint16_t* erase_end;
293 |
294 | const uint16_t* flash_end = get_flash_end();
295 | while (half_word_count > 0) {
296 | /* Avoid writing past the end of flash */
297 | if (dest >= flash_end) {
298 | verified = false;
299 | break;
300 | }
301 |
302 | if (dest >= erase_end || dest < erase_start) {
303 | erase_start = get_flash_page_address(dest);
304 | erase_end = erase_start + (FLASH_PAGE_SIZE)/sizeof(uint16_t);
305 | flash_erase_page((uint32_t)erase_start);
306 | }
307 | flash_program_half_word((uint32_t)dest, *data);
308 | erase_start = dest + 1;
309 | if (*dest != *data) {
310 | verified = false;
311 | break;
312 | }
313 | dest++;
314 | data++;
315 | half_word_count--;
316 | }
317 |
318 | return verified;
319 | }
320 |
--------------------------------------------------------------------------------
/src/target.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #ifndef TARGET_H_INCLUDED
20 | #define TARGET_H_INCLUDED
21 |
22 | #include
23 | #include
24 | #include
25 |
26 | extern void target_clock_setup(void);
27 | extern void target_gpio_setup(void);
28 | extern const usbd_driver* target_usb_init(void);
29 | extern bool target_get_force_bootloader(void);
30 | extern bool target_get_force_app(void);
31 | extern void target_get_serial_number(char* dest, size_t max_chars);
32 | extern size_t target_get_max_firmware_size(void);
33 | extern void target_log(const char* str);
34 | extern void target_relocate_vector_table(void);
35 | extern void target_manifest_app(void);
36 | extern void target_flash_unlock(void);
37 | extern void target_flash_lock(void);
38 | extern bool target_flash_program_array(uint16_t* dest, const uint16_t* data, size_t half_word_count);
39 | extern void target_set_led(int on);
40 |
41 | extern void target_pre_main(void);
42 | #endif
43 |
--------------------------------------------------------------------------------
/src/targets.mk:
--------------------------------------------------------------------------------
1 | ## Copyright (c) 2016, Devan Lai
2 | ##
3 | ## Permission to use, copy, modify, and/or distribute this software
4 | ## for any purpose with or without fee is hereby granted, provided
5 | ## that the above copyright notice and this permission notice
6 | ## appear in all copies.
7 | ##
8 | ## THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
9 | ## WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
10 | ## WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
11 | ## AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
12 | ## CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 | ## LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
14 | ## NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15 | ## CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 |
17 | ifeq ($(TARGET),STM32F103)
18 | TARGET_COMMON_DIR := ./stm32f103
19 | TARGET_SPEC_DIR := ./stm32f103/generic
20 | LDSCRIPT := ./stm32f103/stm32f103x8.ld
21 | ARCH = STM32F1
22 | endif
23 | ifeq ($(TARGET),BLUEPILL)
24 | TARGET_COMMON_DIR := ./stm32f103
25 | TARGET_SPEC_DIR := ./stm32f103/bluepill
26 | LDSCRIPT := ./stm32f103/stm32f103x8.ld
27 | ARCH = STM32F1
28 | DEFS += -DHAVE_LED=1 -DLED_GPIO_PORT=GPIOC -DLED_GPIO_PIN=GPIO13 -DLED_OPEN_DRAIN=1 -DUSES_GPIOC=1
29 | endif
30 | ifeq ($(TARGET),MAPLEMINI)
31 | TARGET_COMMON_DIR := ./stm32f103
32 | TARGET_SPEC_DIR := ./stm32f103/maplemini
33 | LDSCRIPT := ./stm32f103/stm32f103x8.ld
34 | ARCH = STM32F1
35 | endif
36 | ifeq ($(TARGET),STLINK)
37 | TARGET_COMMON_DIR := ./stm32f103
38 | TARGET_SPEC_DIR := ./stm32f103/stlink
39 | LDSCRIPT := ./stm32f103/stm32f103x8.ld
40 | ARCH = STM32F1
41 | endif
42 | ifeq ($(TARGET),PXT32)
43 | TARGET_COMMON_DIR := ./stm32f103
44 | TARGET_SPEC_DIR := ./stm32f103/pxt32
45 | LDSCRIPT := ./stm32f103/stm32f103x8.ld
46 | ARCH = STM32F1
47 | DEFS += -DHAVE_LED=1 -DLED_GPIO_PORT=GPIOB -DLED_GPIO_PIN=GPIO11 -DLED_OPEN_DRAIN=1 -DUSES_GPIOB=1
48 | endif
49 | ifeq ($(TARGET),JACDAC)
50 | TARGET_COMMON_DIR := ./stm32f103
51 | TARGET_SPEC_DIR := ./stm32f103/jacdac
52 | LDSCRIPT := ./stm32f103/stm32f103x8.ld
53 | ARCH = STM32F1
54 | DEFS += -DHAVE_LED=1 -DLED_GPIO_PORT=GPIOB -DLED_GPIO_PIN=GPIO13 -DLED_OPEN_DRAIN=0
55 | endif
56 |
57 | ifndef ARCH
58 | $(error Unknown target $(TARGET))
59 | endif
60 |
--------------------------------------------------------------------------------
/src/uf2.h:
--------------------------------------------------------------------------------
1 | #ifndef UF2FORMAT_H
2 | #define UF2FORMAT_H 1
3 |
4 | #include "uf2cfg.h"
5 | #include "target.h"
6 | #include "config.h"
7 |
8 | #include
9 | #include
10 |
11 | // All entries are little endian.
12 |
13 | #define UF2_MAGIC_START0 0x0A324655UL // "UF2\n"
14 | #define UF2_MAGIC_START1 0x9E5D5157UL // Randomly selected
15 | #define UF2_MAGIC_END 0x0AB16F30UL // Ditto
16 |
17 | // If set, the block is "comment" and should not be flashed to the device
18 | #define UF2_FLAG_NOFLASH 0x00000001
19 | #define UF2_FLAG_FAMILYID_PRESENT 0x00002000
20 |
21 | #define UF2_IS_MY_FAMILY(bl) \
22 | (((bl)->flags & UF2_FLAG_FAMILYID_PRESENT) == 0 || (bl)->familyID == UF2_FAMILY)
23 |
24 | #define MAX_BLOCKS (FLASH_SIZE_OVERRIDE / 256 + 100)
25 | typedef struct {
26 | uint32_t numBlocks;
27 | uint32_t numWritten;
28 | uint8_t writtenMask[MAX_BLOCKS / 8 + 1];
29 | } WriteState;
30 |
31 | typedef struct {
32 | // 32 byte header
33 | uint32_t magicStart0;
34 | uint32_t magicStart1;
35 | uint32_t flags;
36 | uint32_t targetAddr;
37 | uint32_t payloadSize;
38 | uint32_t blockNo;
39 | uint32_t numBlocks;
40 | uint32_t familyID;
41 |
42 | // raw data;
43 | uint8_t data[476];
44 |
45 | // store magic also at the end to limit damage from partial block reads
46 | uint32_t magicEnd;
47 | } UF2_Block;
48 |
49 | typedef struct {
50 | uint8_t version;
51 | uint8_t ep_in;
52 | uint8_t ep_out;
53 | uint8_t reserved0;
54 | uint32_t cbw_tag;
55 | uint32_t blocks_remaining;
56 | uint8_t *buffer;
57 | } UF2_HandoverArgs;
58 |
59 | int write_block(uint32_t lba, const uint8_t *copy_from);
60 | int read_block(uint32_t block_no, uint8_t *data);
61 | void ghostfat_1ms(void);
62 |
63 | typedef void (*UF2_MSC_Handover_Handler)(UF2_HandoverArgs *handover);
64 | typedef void (*UF2_HID_Handover_Handler)(int ep);
65 |
66 | // this is required to be exactly 16 bytes long by the linker script
67 | typedef struct {
68 | void *reserved0;
69 | UF2_HID_Handover_Handler handoverHID;
70 | UF2_MSC_Handover_Handler handoverMSC;
71 | const char *info_uf2;
72 | } UF2_BInfo;
73 |
74 | #define UF2_BINFO ((UF2_BInfo *)(APP_START_ADDRESS - sizeof(UF2_BInfo)))
75 |
76 | static inline bool is_uf2_block(const void *data) {
77 | const UF2_Block *bl = (const UF2_Block *)data;
78 | return bl->magicStart0 == UF2_MAGIC_START0 && bl->magicStart1 == UF2_MAGIC_START1 &&
79 | bl->magicEnd == UF2_MAGIC_END;
80 | }
81 |
82 | static inline bool in_uf2_bootloader_space(const void *addr) {
83 | return USER_FLASH_END <= (uint32_t)addr && (uint32_t)addr < FLASH_SIZE_OVERRIDE;
84 | }
85 |
86 |
87 | #ifdef UF2_DEFINE_HANDOVER
88 | static inline const char *uf2_info(void) {
89 | if (in_uf2_bootloader_space(UF2_BINFO->info_uf2))
90 | return UF2_BINFO->info_uf2;
91 | return "N/A";
92 | }
93 |
94 | static inline void hf2_handover(uint8_t ep) {
95 | const char *board_info = UF2_BINFO->info_uf2;
96 | UF2_HID_Handover_Handler fn = UF2_BINFO->handoverHID;
97 |
98 | if (in_uf2_bootloader_space(board_info) && in_uf2_bootloader_space((const void *)fn) &&
99 | ((uint32_t)fn & 1)) {
100 | // Pass control to bootloader; never returns
101 | fn(ep & 0xf);
102 | }
103 | }
104 |
105 | // the ep_in/ep_out are without the 0x80 mask
106 | // cbw_tag is in the same bit format as it came
107 | static inline void check_uf2_handover(uint8_t *buffer, uint32_t blocks_remaining, uint8_t ep_in,
108 | uint8_t ep_out, uint32_t cbw_tag) {
109 | if (!is_uf2_block(buffer))
110 | return;
111 |
112 | const char *board_info = UF2_BINFO->info_uf2;
113 | UF2_MSC_Handover_Handler fn = UF2_BINFO->handoverMSC;
114 |
115 | if (in_uf2_bootloader_space(board_info) && in_uf2_bootloader_space((const void *)fn) &&
116 | ((uint32_t)fn & 1)) {
117 | UF2_HandoverArgs hand = {
118 | 1, ep_in, ep_out, 0, cbw_tag, blocks_remaining, buffer,
119 | };
120 | // Pass control to bootloader; never returns
121 | fn(&hand);
122 | }
123 | }
124 | #endif
125 |
126 | #endif
127 |
--------------------------------------------------------------------------------
/src/uf2cfg.h:
--------------------------------------------------------------------------------
1 | #define PRODUCT_NAME "STM32 Board"
2 | #define BOARD_ID "STM32F103-generic-v0"
3 | #define INDEX_URL "https://maker.makecode.com"
4 | #define UF2_NUM_BLOCKS 8000
5 | #define VOLUME_LABEL "STM32"
6 | // where the UF2 files are allowed to write data - we allow MBR, since it seems part of the softdevice .hex file
7 | #define USER_FLASH_START (uint32_t)(APP_BASE_ADDRESS)
8 | #define USER_FLASH_END (0x08000000+FLASH_SIZE_OVERRIDE)
9 |
--------------------------------------------------------------------------------
/src/usb_conf.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #include
20 | #include
21 | #include
22 |
23 | #include "target.h"
24 | #include "webusb.h"
25 |
26 | #include
27 |
28 | #include "usb_conf.h"
29 |
30 | static const struct usb_device_descriptor dev = {
31 | .bLength = USB_DT_DEVICE_SIZE,
32 | .bDescriptorType = USB_DT_DEVICE,
33 | .bcdUSB = 0x0210,
34 | .bDeviceClass = 0,
35 | .bDeviceSubClass = 0,
36 | .bDeviceProtocol = 0,
37 | .bMaxPacketSize0 = 64,
38 | .idVendor = USB_VID,
39 | .idProduct = USB_PID,
40 | .bcdDevice = 0x0110,
41 | .iManufacturer = 1,
42 | .iProduct = 2,
43 | .iSerialNumber = 3,
44 | .bNumConfigurations = 1,
45 | };
46 |
47 | static const struct usb_interface_descriptor dfu_iface = {
48 | .bLength = USB_DT_INTERFACE_SIZE,
49 | .bDescriptorType = USB_DT_INTERFACE,
50 | .bInterfaceNumber = INTF_DFU,
51 | .bAlternateSetting = 0,
52 | .bNumEndpoints = 0,
53 | .bInterfaceClass = 0xFE,
54 | .bInterfaceSubClass = 1,
55 | .bInterfaceProtocol = 2,
56 | .iInterface = 4,
57 |
58 | .endpoint = NULL,
59 | };
60 |
61 | static const struct usb_endpoint_descriptor msc_endp[] = {{
62 | .bLength = USB_DT_ENDPOINT_SIZE,
63 | .bDescriptorType = USB_DT_ENDPOINT,
64 | .bEndpointAddress = 0x01,
65 | .bmAttributes = USB_ENDPOINT_ATTR_BULK,
66 | .wMaxPacketSize = 64,
67 | .bInterval = 0,
68 | }, {
69 | .bLength = USB_DT_ENDPOINT_SIZE,
70 | .bDescriptorType = USB_DT_ENDPOINT,
71 | .bEndpointAddress = 0x82,
72 | .bmAttributes = USB_ENDPOINT_ATTR_BULK,
73 | .wMaxPacketSize = 64,
74 | .bInterval = 0,
75 | }};
76 |
77 | static const struct usb_interface_descriptor msc_iface = {
78 | .bLength = USB_DT_INTERFACE_SIZE,
79 | .bDescriptorType = USB_DT_INTERFACE,
80 | .bInterfaceNumber = INTF_MSC,
81 | .bAlternateSetting = 0,
82 | .bNumEndpoints = 2,
83 | .bInterfaceClass = USB_CLASS_MSC,
84 | .bInterfaceSubClass = USB_MSC_SUBCLASS_SCSI,
85 | .bInterfaceProtocol = USB_MSC_PROTOCOL_BBB,
86 | .iInterface = 0,
87 | .endpoint = msc_endp,
88 | .extra = NULL,
89 | .extralen = 0
90 | };
91 |
92 | static const struct usb_interface interfaces[] = {
93 | /* DFU interface */
94 | {
95 | .num_altsetting = 1,
96 | .altsetting = &dfu_iface,
97 | },
98 | {
99 | .num_altsetting = 1,
100 | .altsetting = &msc_iface,
101 | },
102 | };
103 |
104 | static const struct usb_config_descriptor config = {
105 | .bLength = USB_DT_CONFIGURATION_SIZE,
106 | .bDescriptorType = USB_DT_CONFIGURATION,
107 | .wTotalLength = 0,
108 | .bNumInterfaces = sizeof(interfaces)/sizeof(struct usb_interface),
109 | .bConfigurationValue = 1,
110 | .iConfiguration = 0,
111 | .bmAttributes = 0xC0,
112 | .bMaxPower = 0x32,
113 |
114 | .interface = interfaces,
115 | };
116 |
117 | static const struct usb_device_capability_descriptor* capabilities[] = {
118 | (const struct usb_device_capability_descriptor*)&webusb_platform,
119 | };
120 |
121 | static const struct usb_bos_descriptor bos = {
122 | .bLength = USB_DT_BOS_SIZE,
123 | .bDescriptorType = USB_DT_BOS,
124 | .wTotalLength = USB_DT_BOS_SIZE + sizeof(webusb_platform),
125 | .bNumDeviceCaps = sizeof(capabilities)/sizeof(capabilities[0]),
126 | .capabilities = capabilities
127 | };
128 |
129 | static char serial_number[USB_SERIAL_NUM_LENGTH+1];
130 |
131 | static const char *usb_strings[] = {
132 | "Devanarchy",
133 | "DAPBoot DFU Bootloader",
134 | serial_number,
135 | "DAPBoot DFU"
136 | };
137 |
138 | /* Buffer to be used for control requests. */
139 | static uint8_t usbd_control_buffer[USB_CONTROL_BUF_SIZE] __attribute__ ((aligned (2)));
140 |
141 | void usb_set_serial_number(const char* serial) {
142 | serial_number[0] = '\0';
143 | if (serial) {
144 | strncpy(serial_number, serial, USB_SERIAL_NUM_LENGTH);
145 | serial_number[USB_SERIAL_NUM_LENGTH] = '\0';
146 | }
147 | }
148 |
149 | usbd_device* usb_setup(void) {
150 | int num_strings = sizeof(usb_strings)/sizeof(const char*);
151 |
152 | const usbd_driver* driver = target_usb_init();
153 | usbd_device* usbd_dev = usbd_init(driver, &dev, &config, &bos,
154 | usb_strings, num_strings,
155 | usbd_control_buffer, sizeof(usbd_control_buffer));
156 |
157 | return usbd_dev;
158 | }
159 |
--------------------------------------------------------------------------------
/src/usb_conf.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #ifndef USB_CONF_H_INCLUDED
20 | #define USB_CONF_H_INCLUDED
21 |
22 | #include
23 |
24 | #define USB_VID 0x1209
25 | #define USB_PID 0xdb42
26 | #define USB_CONTROL_BUF_SIZE 1024
27 | #define USB_SERIAL_NUM_LENGTH 24
28 | #define INTF_DFU 0
29 | #define INTF_MSC 1
30 |
31 | extern void usb_set_serial_number(const char* serial);
32 | extern usbd_device* usb_setup(void);
33 |
34 | #endif
35 |
--------------------------------------------------------------------------------
/src/usb_msc.c:
--------------------------------------------------------------------------------
1 | /*
2 | * This file is part of the libopencm3 project.
3 | *
4 | * Copyright (C) 2013 Weston Schmidt
5 | * Copyright (C) 2013 Pavol Rusnak
6 | *
7 | * This library is free software: you can redistribute it and/or modify
8 | * it under the terms of the GNU Lesser General Public License as published by
9 | * the Free Software Foundation, either version 3 of the License, or
10 | * (at your option) any later version.
11 | *
12 | * This library is distributed in the hope that it will be useful,
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | * GNU Lesser General Public License for more details.
16 | *
17 | * You should have received a copy of the GNU Lesser General Public License
18 | * along with this library. If not, see .
19 | */
20 |
21 | #include
22 | #include
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include "../lib/usb/usb_private.h"
28 |
29 | #include "dmesg.h"
30 | // #define LOG DMESG
31 | #define LOG NOOP
32 |
33 | /* Definitions of Mass Storage Class from:
34 | *
35 | * (A) "Universal Serial Bus Mass Storage Class Bulk-Only Transport
36 | * Revision 1.0"
37 | *
38 | * (B) "Universal Serial Bus Mass Storage Class Specification Overview
39 | * Revision 1.0"
40 | */
41 |
42 | /* Command Block Wrapper */
43 | #define CBW_SIGNATURE 0x43425355
44 | #define CBW_STATUS_SUCCESS 0
45 | #define CBW_STATUS_FAILED 1
46 | #define CBW_STATUS_PHASE_ERROR 2
47 |
48 | /* Command Status Wrapper */
49 | #define CSW_SIGNATURE 0x53425355
50 | #define CSW_STATUS_SUCCESS 0
51 | #define CSW_STATUS_FAILED 1
52 | #define CSW_STATUS_PHASE_ERROR 2
53 |
54 | /* Implemented SCSI Commands */
55 | #define SCSI_TEST_UNIT_READY 0x00
56 | #define SCSI_REQUEST_SENSE 0x03
57 | #define SCSI_FORMAT_UNIT 0x04
58 | #define SCSI_READ_6 0x08
59 | #define SCSI_WRITE_6 0x0A
60 | #define SCSI_INQUIRY 0x12
61 | #define SCSI_MODE_SENSE_6 0x1A
62 | #define SCSI_SEND_DIAGNOSTIC 0x1D
63 | #define SCSI_READ_CAPACITY 0x25
64 | #define SCSI_READ_10 0x28
65 |
66 |
67 | /* Required SCSI Commands */
68 |
69 | /* Optional SCSI Commands */
70 | #define SCSI_REPORT_LUNS 0xA0
71 | #define SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
72 | #define SCSI_MODE_SELECT_6 0x15
73 | #define SCSI_MODE_SELECT_10 0x55
74 | #define SCSI_MODE_SENSE_10 0x5A
75 | #define SCSI_READ_12 0xA8
76 | #define SCSI_READ_FORMAT_CAPACITIES 0x23
77 | #define SCSI_READ_TOC_PMA_ATIP 0x43
78 | #define SCSI_START_STOP_UNIT 0x1B
79 | #define SCSI_SYNCHRONIZE_CACHE 0x35
80 | #define SCSI_VERIFY 0x2F
81 | #define SCSI_WRITE_10 0x2A
82 | #define SCSI_WRITE_12 0xAA
83 |
84 | /* The sense codes */
85 | enum sbc_sense_key {
86 | SBC_SENSE_KEY_NO_SENSE = 0x00,
87 | SBC_SENSE_KEY_RECOVERED_ERROR = 0x01,
88 | SBC_SENSE_KEY_NOT_READY = 0x02,
89 | SBC_SENSE_KEY_MEDIUM_ERROR = 0x03,
90 | SBC_SENSE_KEY_HARDWARE_ERROR = 0x04,
91 | SBC_SENSE_KEY_ILLEGAL_REQUEST = 0x05,
92 | SBC_SENSE_KEY_UNIT_ATTENTION = 0x06,
93 | SBC_SENSE_KEY_DATA_PROTECT = 0x07,
94 | SBC_SENSE_KEY_BLANK_CHECK = 0x08,
95 | SBC_SENSE_KEY_VENDOR_SPECIFIC = 0x09,
96 | SBC_SENSE_KEY_COPY_ABORTED = 0x0A,
97 | SBC_SENSE_KEY_ABORTED_COMMAND = 0x0B,
98 | SBC_SENSE_KEY_VOLUME_OVERFLOW = 0x0D,
99 | SBC_SENSE_KEY_MISCOMPARE = 0x0E
100 | };
101 |
102 | enum sbc_asc {
103 | SBC_ASC_NO_ADDITIONAL_SENSE_INFORMATION = 0x00,
104 | SBC_ASC_PERIPHERAL_DEVICE_WRITE_FAULT = 0x03,
105 | SBC_ASC_LOGICAL_UNIT_NOT_READY = 0x04,
106 | SBC_ASC_UNRECOVERED_READ_ERROR = 0x11,
107 | SBC_ASC_INVALID_COMMAND_OPERATION_CODE = 0x20,
108 | SBC_ASC_LBA_OUT_OF_RANGE = 0x21,
109 | SBC_ASC_INVALID_FIELD_IN_CDB = 0x24,
110 | SBC_ASC_WRITE_PROTECTED = 0x27,
111 | SBC_ASC_NOT_READY_TO_READY_CHANGE = 0x28,
112 | SBC_ASC_FORMAT_ERROR = 0x31,
113 | SBC_ASC_MEDIUM_NOT_PRESENT = 0x3A
114 | };
115 |
116 | enum sbc_ascq {
117 | SBC_ASCQ_NA = 0x00,
118 | SBC_ASCQ_FORMAT_COMMAND_FAILED = 0x01,
119 | SBC_ASCQ_INITIALIZING_COMMAND_REQUIRED = 0x02,
120 | SBC_ASCQ_OPERATION_IN_PROGRESS = 0x07
121 | };
122 |
123 | enum trans_event {
124 | EVENT_CBW_VALID,
125 | EVENT_NEED_STATUS
126 | };
127 |
128 | struct usb_msc_cbw {
129 | uint32_t dCBWSignature;
130 | uint32_t dCBWTag;
131 | uint32_t dCBWDataTransferLength;
132 | uint8_t bmCBWFlags;
133 | uint8_t bCBWLUN;
134 | uint8_t bCBWCBLength;
135 | uint8_t CBWCB[16];
136 | } __attribute__((packed));
137 |
138 | struct usb_msc_csw {
139 | uint32_t dCSWSignature;
140 | uint32_t dCSWTag;
141 | uint32_t dCSWDataResidue;
142 | uint8_t bCSWStatus;
143 | } __attribute__((packed));
144 |
145 | struct sbc_sense_info {
146 | uint8_t key;
147 | uint8_t asc;
148 | uint8_t ascq;
149 | };
150 |
151 | struct usb_msc_trans {
152 | uint8_t cbw_cnt; /* Read until 31 bytes */
153 | union {
154 | struct usb_msc_cbw cbw;
155 | uint8_t buf[1];
156 | } cbw;
157 |
158 | uint32_t bytes_to_read;
159 | uint32_t bytes_to_write;
160 | uint32_t byte_count; /* Either read until equal to
161 | bytes_to_read or write until equal
162 | to bytes_to_write. */
163 | uint32_t lba_start;
164 | uint32_t block_count;
165 | uint32_t current_block;
166 |
167 | uint8_t msd_buf[512];
168 |
169 | bool csw_valid;
170 | uint8_t csw_sent; /* Write until 13 bytes */
171 | union {
172 | struct usb_msc_csw csw;
173 | uint8_t buf[1];
174 | } csw;
175 | };
176 |
177 | struct _usbd_mass_storage {
178 | usbd_device *usbd_dev;
179 | uint8_t ep_in;
180 | uint8_t ep_in_size;
181 | uint8_t ep_out;
182 | uint8_t ep_out_size;
183 |
184 | const char *vendor_id;
185 | const char *product_id;
186 | const char *product_revision_level;
187 | uint32_t block_count;
188 |
189 | int (*read_block)(uint32_t lba, uint8_t *copy_to);
190 | int (*write_block)(uint32_t lba, const uint8_t *copy_from);
191 |
192 | void (*lock)(void);
193 | void (*unlock)(void);
194 |
195 | struct usb_msc_trans trans;
196 | struct sbc_sense_info sense;
197 | };
198 |
199 | static usbd_mass_storage _mass_storage;
200 |
201 | /*-- SCSI Base Responses -----------------------------------------------------*/
202 |
203 | static const uint8_t _spc3_inquiry_response[36] = {
204 | 0x00, /* Byte 0: Peripheral Qualifier = 0, Peripheral Device Type = 0 */
205 | 0x80, /* Byte 1: RMB = 1, Reserved = 0 */
206 | 0x04, /* Byte 2: Version = 0 */
207 | 0x02, /* Byte 3: Obsolete = 0, NormACA = 0, HiSup = 0, Response Data Format = 2 */
208 | 0x20, /* Byte 4: Additional Length (n-4) = 31 + 4 */
209 | 0x00, /* Byte 5: SCCS = 0, ACC = 0, TPGS = 0, 3PC = 0, Reserved = 0, Protect = 0 */
210 | 0x00, /* Byte 6: BQue = 0, EncServ = 0, VS = 0, MultiP = 0, MChngr = 0, Obsolete = 0, Addr16 = 0 */
211 | 0x00, /* Byte 7: Obsolete = 0, Wbus16 = 0, Sync = 0, Linked = 0, CmdQue = 0, VS = 0 */
212 | /* Byte 8 - Byte 15: Vendor Identification */
213 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
214 | /* Byte 16 - Byte 31: Product Identification */
215 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
216 | 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
217 | /* Byte 32 - Byte 35: Product Revision Level */
218 | 0x20, 0x20, 0x20, 0x20
219 | };
220 |
221 | static const uint8_t _spc3_request_sense[18] = {
222 | 0x70, /* Byte 0: VALID = 0, Response Code = 112 */
223 | 0x00, /* Byte 1: Obsolete = 0 */
224 | 0x00, /* Byte 2: Filemark = 0, EOM = 0, ILI = 0, Reserved = 0, Sense Key = 0 */
225 | /* Byte 3 - Byte 6: Information = 0 */
226 | 0, 0, 0, 0,
227 | 0x0a, /* Byte 7: Additional Sense Length = 10 */
228 | /* Byte 8 - Byte 11: Command Specific Info = 0 */
229 | 0, 0, 0, 0,
230 | 0x00, /* Byte 12: Additional Sense Code (ASC) = 0 */
231 | 0x00, /* Byte 13: Additional Sense Code Qualifier (ASCQ) = 0 */
232 | 0x00, /* Byte 14: Field Replaceable Unit Code (FRUC) = 0 */
233 | 0x00, /* Byte 15: SKSV = 0, SenseKeySpecific[0] = 0 */
234 | 0x00, /* Byte 16: SenseKeySpecific[0] = 0 */
235 | 0x00 /* Byte 17: SenseKeySpecific[0] = 0 */
236 | };
237 |
238 | /*-- SCSI Layer --------------------------------------------------------------*/
239 |
240 | static void set_sbc_status(usbd_mass_storage *ms,
241 | enum sbc_sense_key key,
242 | enum sbc_asc asc,
243 | enum sbc_ascq ascq)
244 | {
245 | LOG("SBC st %d %d %d", key, asc, ascq);
246 | ms->sense.key = (uint8_t) key;
247 | ms->sense.asc = (uint8_t) asc;
248 | ms->sense.ascq = (uint8_t) ascq;
249 | }
250 |
251 | static void set_sbc_status_good(usbd_mass_storage *ms)
252 | {
253 | set_sbc_status(ms,
254 | SBC_SENSE_KEY_NO_SENSE,
255 | SBC_ASC_NO_ADDITIONAL_SENSE_INFORMATION,
256 | SBC_ASCQ_NA);
257 | }
258 |
259 | static uint8_t *get_cbw_buf(struct usb_msc_trans *trans)
260 | {
261 | return &trans->cbw.cbw.CBWCB[0];
262 | }
263 |
264 | static void scsi_read_6(usbd_mass_storage *ms,
265 | struct usb_msc_trans *trans,
266 | enum trans_event event)
267 | {
268 | if (EVENT_CBW_VALID == event) {
269 | uint8_t *buf;
270 |
271 | buf = get_cbw_buf(trans);
272 |
273 | trans->lba_start = (buf[2] << 8) | buf[3];
274 | trans->block_count = buf[4];
275 | trans->current_block = 0;
276 |
277 | /* TODO: Check the lba & block_count for range. */
278 |
279 | /* both are in terms of 512 byte blocks, so shift by 9 */
280 | trans->bytes_to_write = trans->block_count << 9;
281 |
282 | set_sbc_status_good(ms);
283 | }
284 | }
285 |
286 | static void scsi_write_6(usbd_mass_storage *ms,
287 | struct usb_msc_trans *trans,
288 | enum trans_event event)
289 | {
290 | (void) ms;
291 |
292 | if (EVENT_CBW_VALID == event) {
293 | uint8_t *buf;
294 |
295 | buf = get_cbw_buf(trans);
296 |
297 | trans->lba_start = ((0x1f & buf[1]) << 16)
298 | | (buf[2] << 8) | buf[3];
299 | trans->block_count = buf[4];
300 | trans->current_block = 0;
301 |
302 | trans->bytes_to_read = trans->block_count << 9;
303 | }
304 | }
305 |
306 | static void scsi_write_10(usbd_mass_storage *ms,
307 | struct usb_msc_trans *trans,
308 | enum trans_event event)
309 | {
310 | (void) ms;
311 |
312 | if (EVENT_CBW_VALID == event) {
313 | uint8_t *buf;
314 |
315 | buf = get_cbw_buf(trans);
316 |
317 | trans->lba_start = (buf[2] << 24) | (buf[3] << 16) |
318 | (buf[4] << 8) | buf[5];
319 | trans->block_count = (buf[7] << 8) | buf[8];
320 | trans->current_block = 0;
321 |
322 | trans->bytes_to_read = trans->block_count << 9;
323 | }
324 | }
325 |
326 | static void scsi_read_10(usbd_mass_storage *ms,
327 | struct usb_msc_trans *trans,
328 | enum trans_event event)
329 | {
330 | if (EVENT_CBW_VALID == event) {
331 | uint8_t *buf;
332 |
333 | buf = get_cbw_buf(trans);
334 |
335 | trans->lba_start = (buf[2] << 24) | (buf[3] << 16)
336 | | (buf[4] << 8) | buf[5];
337 | trans->block_count = (buf[7] << 8) | buf[8];
338 |
339 | /* TODO: Check the lba & block_count for range. */
340 |
341 | /* both are in terms of 512 byte blocks, so shift by 9 */
342 | trans->bytes_to_write = trans->block_count << 9;
343 |
344 | set_sbc_status_good(ms);
345 | }
346 | }
347 |
348 | static void scsi_read_capacity(usbd_mass_storage *ms,
349 | struct usb_msc_trans *trans,
350 | enum trans_event event)
351 | {
352 | if (EVENT_CBW_VALID == event) {
353 | trans->msd_buf[0] = ms->block_count >> 24;
354 | trans->msd_buf[1] = 0xff & (ms->block_count >> 16);
355 | trans->msd_buf[2] = 0xff & (ms->block_count >> 8);
356 | trans->msd_buf[3] = 0xff & ms->block_count;
357 |
358 | /* Block size: 512 */
359 | trans->msd_buf[4] = 0;
360 | trans->msd_buf[5] = 0;
361 | trans->msd_buf[6] = 2;
362 | trans->msd_buf[7] = 0;
363 | trans->bytes_to_write = 8;
364 | set_sbc_status_good(ms);
365 | }
366 | }
367 |
368 | static void scsi_read_format_capacity(usbd_mass_storage *ms,
369 | struct usb_msc_trans *trans,
370 | enum trans_event event)
371 | {
372 | if (EVENT_CBW_VALID == event) {
373 | trans->msd_buf[0] = 0;
374 | trans->msd_buf[1] = 0;
375 | trans->msd_buf[2] = 0;
376 | trans->msd_buf[3] = 8;
377 | trans->msd_buf[4] = ms->block_count >> 24;
378 | trans->msd_buf[5] = 0xff & (ms->block_count >> 16);
379 | trans->msd_buf[6] = 0xff & (ms->block_count >> 8);
380 | trans->msd_buf[7] = 0xff & ms->block_count;
381 | trans->msd_buf[8] = 2; // formatted media
382 | trans->msd_buf[9] = 0;
383 | trans->msd_buf[10] = 512>>8; // block size
384 | trans->msd_buf[11] = 0;
385 | trans->bytes_to_write = 12;
386 | set_sbc_status_good(ms);
387 | }
388 | }
389 |
390 | static void scsi_format_unit(usbd_mass_storage *ms,
391 | struct usb_msc_trans *trans,
392 | enum trans_event event)
393 | {
394 | if (EVENT_CBW_VALID == event) {
395 | uint32_t i;
396 |
397 | memset(trans->msd_buf, 0, 512);
398 |
399 | for (i = 0; i < ms->block_count; i++) {
400 | (*ms->write_block)(i, trans->msd_buf);
401 | }
402 |
403 | set_sbc_status_good(ms);
404 | }
405 | }
406 |
407 | static void scsi_request_sense(usbd_mass_storage *ms,
408 | struct usb_msc_trans *trans,
409 | enum trans_event event)
410 | {
411 | if (EVENT_CBW_VALID == event) {
412 | uint8_t *buf;
413 |
414 | buf = &trans->cbw.cbw.CBWCB[0];
415 |
416 | trans->bytes_to_write = buf[4]; /* allocation length */
417 | memcpy(trans->msd_buf, _spc3_request_sense,
418 | sizeof(_spc3_request_sense));
419 |
420 | trans->msd_buf[2] = ms->sense.key;
421 | trans->msd_buf[12] = ms->sense.asc;
422 | trans->msd_buf[13] = ms->sense.ascq;
423 | }
424 | }
425 |
426 | static void scsi_mode_sense_6(usbd_mass_storage *ms,
427 | struct usb_msc_trans *trans,
428 | enum trans_event event)
429 | {
430 | (void) ms;
431 |
432 | if (EVENT_CBW_VALID == event) {
433 | #if 0
434 | uint8_t *buf;
435 | uint8_t page_code;
436 | uint8_t allocation_length;
437 |
438 | buf = &trans->cbw.cbw.CBWCB[0];
439 | page_code = buf[2];
440 | allocation_length = buf[4];
441 |
442 | if (0x1C == page_code) { /* Informational Exceptions */
443 | #endif
444 | trans->bytes_to_write = 4;
445 |
446 | trans->msd_buf[0] = 3; /* Num bytes that follow */
447 | trans->msd_buf[1] = 0; /* Medium Type */
448 | trans->msd_buf[2] = 0; /* Device specific param */
449 | trans->csw.csw.dCSWDataResidue = 4;
450 | #if 0
451 | } else if (0x01 == page_code) { /* Error recovery */
452 | } else if (0x3F == page_code) { /* All */
453 | } else {
454 | /* Error */
455 | trans->csw.csw.bCSWStatus = CSW_STATUS_FAILED;
456 | set_sbc_status(ms,
457 | SBC_SENSE_KEY_ILLEGAL_REQUEST,
458 | SBC_ASC_INVALID_FIELD_IN_CDB,
459 | SBC_ASCQ_NA);
460 | }
461 | #endif
462 | }
463 | }
464 |
465 | static void scsi_inquiry(usbd_mass_storage *ms,
466 | struct usb_msc_trans *trans,
467 | enum trans_event event)
468 | {
469 | if (EVENT_CBW_VALID == event) {
470 | uint8_t evpd;
471 | uint8_t *buf;
472 |
473 | buf = get_cbw_buf(trans);
474 | evpd = 1 & buf[1];
475 |
476 | evpd = 0; // force response always, otherwise it fails on Windows
477 |
478 | if (0 == evpd) {
479 | size_t len;
480 | trans->bytes_to_write = sizeof(_spc3_inquiry_response);
481 | memcpy(trans->msd_buf, _spc3_inquiry_response,
482 | sizeof(_spc3_inquiry_response));
483 |
484 | len = strlen(ms->vendor_id);
485 | len = MIN(len, 8);
486 | memcpy(&trans->msd_buf[8], ms->vendor_id, len);
487 |
488 | len = strlen(ms->product_id);
489 | len = MIN(len, 16);
490 | memcpy(&trans->msd_buf[16], ms->product_id, len);
491 |
492 | len = strlen(ms->product_revision_level);
493 | len = MIN(len, 4);
494 | memcpy(&trans->msd_buf[32], ms->product_revision_level,
495 | len);
496 |
497 | trans->csw.csw.dCSWDataResidue =
498 | sizeof(_spc3_inquiry_response);
499 |
500 | set_sbc_status_good(ms);
501 | } else {
502 | /* TODO: Add VPD 0x83 support */
503 | /* TODO: Add VPD 0x00 support */
504 | }
505 | }
506 | }
507 |
508 | static void scsi_command(usbd_mass_storage *ms,
509 | struct usb_msc_trans *trans,
510 | enum trans_event event)
511 | {
512 | if (EVENT_CBW_VALID == event) {
513 | /* Setup the default success */
514 | trans->csw_sent = 0;
515 | trans->csw.csw.dCSWSignature = CSW_SIGNATURE;
516 | trans->csw.csw.dCSWTag = trans->cbw.cbw.dCBWTag;
517 | trans->csw.csw.dCSWDataResidue = 0;
518 | trans->csw.csw.bCSWStatus = CSW_STATUS_SUCCESS;
519 |
520 | trans->bytes_to_write = 0;
521 | trans->bytes_to_read = 0;
522 | trans->byte_count = 0;
523 | }
524 |
525 | LOG("SCSI %x", trans->cbw.cbw.CBWCB[0]);
526 |
527 | switch (trans->cbw.cbw.CBWCB[0]) {
528 | case SCSI_TEST_UNIT_READY:
529 | case SCSI_SEND_DIAGNOSTIC:
530 | /* Do nothing, just send the success. */
531 | set_sbc_status_good(ms);
532 | break;
533 | case SCSI_FORMAT_UNIT:
534 | scsi_format_unit(ms, trans, event);
535 | break;
536 | case SCSI_REQUEST_SENSE:
537 | scsi_request_sense(ms, trans, event);
538 | break;
539 | case SCSI_MODE_SENSE_6:
540 | scsi_mode_sense_6(ms, trans, event);
541 | break;
542 | case SCSI_READ_6:
543 | scsi_read_6(ms, trans, event);
544 | break;
545 | case SCSI_INQUIRY:
546 | scsi_inquiry(ms, trans, event);
547 | break;
548 | case SCSI_READ_CAPACITY:
549 | scsi_read_capacity(ms, trans, event);
550 | break;
551 | case SCSI_READ_FORMAT_CAPACITIES:
552 | scsi_read_format_capacity(ms, trans, event);
553 | break;
554 | case SCSI_READ_10:
555 | scsi_read_10(ms, trans, event);
556 | break;
557 | case SCSI_WRITE_6:
558 | scsi_write_6(ms, trans, event);
559 | break;
560 | case SCSI_WRITE_10:
561 | scsi_write_10(ms, trans, event);
562 | break;
563 | default:
564 | set_sbc_status(ms, SBC_SENSE_KEY_ILLEGAL_REQUEST,
565 | SBC_ASC_INVALID_COMMAND_OPERATION_CODE,
566 | SBC_ASCQ_NA);
567 |
568 | trans->bytes_to_write = 0;
569 | trans->bytes_to_read = 0;
570 | trans->csw.csw.bCSWStatus = CSW_STATUS_FAILED;
571 | break;
572 | }
573 | }
574 |
575 | /*-- USB Mass Storage Layer --------------------------------------------------*/
576 |
577 | /** @brief Handle the USB 'OUT' requests. */
578 | static void msc_data_rx_cb(usbd_device *usbd_dev, uint8_t ep)
579 | {
580 | usbd_mass_storage *ms;
581 | struct usb_msc_trans *trans;
582 | int len, max_len, left;
583 | void *p;
584 |
585 | ms = &_mass_storage;
586 | trans = &ms->trans;
587 |
588 | /* RX only */
589 | left = sizeof(struct usb_msc_cbw) - trans->cbw_cnt;
590 | if (0 < left) {
591 | max_len = MIN(ms->ep_out_size, left);
592 | p = &trans->cbw.buf[0x1ff & trans->cbw_cnt];
593 | len = usbd_ep_read_packet(usbd_dev, ep, p, max_len);
594 | trans->cbw_cnt += len;
595 |
596 | if (sizeof(struct usb_msc_cbw) == trans->cbw_cnt) {
597 | scsi_command(ms, trans, EVENT_CBW_VALID);
598 | if (trans->byte_count < trans->bytes_to_read) {
599 | /* We must wait until there is something to
600 | * read again. */
601 | return;
602 | }
603 | }
604 | }
605 |
606 | if (trans->byte_count < trans->bytes_to_read) {
607 | if (0 < trans->block_count) {
608 | if ((0 == trans->byte_count) && (NULL != ms->lock)) {
609 | (*ms->lock)();
610 | }
611 | }
612 |
613 | left = trans->bytes_to_read - trans->byte_count;
614 | max_len = MIN(ms->ep_out_size, left);
615 | p = &trans->msd_buf[0x1ff & trans->byte_count];
616 | len = usbd_ep_read_packet(usbd_dev, ep, p, max_len);
617 | trans->byte_count += len;
618 |
619 | if (0 < trans->block_count) {
620 | if (0 == (0x1ff & trans->byte_count)) {
621 | uint32_t lba;
622 |
623 | lba = trans->lba_start + trans->current_block;
624 | if (0 != (*ms->write_block)(lba,
625 | trans->msd_buf)) {
626 | /* Error */
627 | }
628 | trans->current_block++;
629 | }
630 | }
631 |
632 | /* Fix "writes aren't acknowledged" bug on Linux (PR #409) */
633 | if (false == trans->csw_valid) {
634 | scsi_command(ms, trans, EVENT_NEED_STATUS);
635 | trans->csw_valid = true;
636 | }
637 | left = sizeof(struct usb_msc_csw) - trans->csw_sent;
638 | if (0 < left) {
639 | max_len = MIN(ms->ep_out_size, left);
640 | p = &trans->csw.buf[trans->csw_sent];
641 | len = usbd_ep_write_packet(usbd_dev, ms->ep_in, p,
642 | max_len);
643 | trans->csw_sent += len;
644 | }
645 |
646 | } else if (trans->byte_count < trans->bytes_to_write) {
647 | if (0 < trans->block_count) {
648 | if ((0 == trans->byte_count) && (NULL != ms->lock)) {
649 | (*ms->lock)();
650 | }
651 |
652 | if (0 == (0x1ff & trans->byte_count)) {
653 | uint32_t lba;
654 |
655 | lba = trans->lba_start + trans->current_block;
656 | if (0 != (*ms->read_block)(lba,
657 | trans->msd_buf)) {
658 | /* Error */
659 | }
660 | trans->current_block++;
661 | }
662 | }
663 |
664 | left = trans->bytes_to_write - trans->byte_count;
665 | max_len = MIN(ms->ep_out_size, left);
666 | p = &trans->msd_buf[0x1ff & trans->byte_count];
667 | len = usbd_ep_write_packet(usbd_dev, ms->ep_in, p, max_len);
668 | trans->byte_count += len;
669 | } else {
670 | if (0 < trans->block_count) {
671 | if (trans->current_block == trans->block_count) {
672 | uint32_t lba;
673 |
674 | lba = trans->lba_start + trans->current_block;
675 | if (0 != (*ms->write_block)(lba,
676 | trans->msd_buf)) {
677 | /* Error */
678 | }
679 |
680 | trans->current_block = 0;
681 | if (NULL != ms->unlock) {
682 | (*ms->unlock)();
683 | }
684 | }
685 | }
686 | if (false == trans->csw_valid) {
687 | scsi_command(ms, trans, EVENT_NEED_STATUS);
688 | trans->csw_valid = true;
689 | }
690 |
691 | left = sizeof(struct usb_msc_csw) - trans->csw_sent;
692 | if (0 < left) {
693 | max_len = MIN(ms->ep_out_size, left);
694 | p = &trans->csw.buf[trans->csw_sent];
695 | len = usbd_ep_write_packet(usbd_dev, ms->ep_in, p,
696 | max_len);
697 | trans->csw_sent += len;
698 | }
699 | }
700 | }
701 |
702 | /** @brief Handle the USB 'IN' requests. */
703 | static void msc_data_tx_cb(usbd_device *usbd_dev, uint8_t ep)
704 | {
705 | usbd_mass_storage *ms;
706 | struct usb_msc_trans *trans;
707 | int len, max_len, left;
708 | void *p;
709 |
710 | ms = &_mass_storage;
711 | trans = &ms->trans;
712 |
713 | if (trans->byte_count < trans->bytes_to_write) {
714 | if (0 < trans->block_count) {
715 | if (0 == (0x1ff & trans->byte_count)) {
716 | uint32_t lba;
717 |
718 | lba = trans->lba_start + trans->current_block;
719 | if (0 != (*ms->read_block)(lba,
720 | trans->msd_buf)) {
721 | /* Error */
722 | }
723 | trans->current_block++;
724 | }
725 | }
726 |
727 | left = trans->bytes_to_write - trans->byte_count;
728 | max_len = MIN(ms->ep_out_size, left);
729 | p = &trans->msd_buf[0x1ff & trans->byte_count];
730 | len = usbd_ep_write_packet(usbd_dev, ep, p, max_len);
731 | trans->byte_count += len;
732 | } else {
733 | if (0 < trans->block_count) {
734 | if (trans->current_block == trans->block_count) {
735 | trans->current_block = 0;
736 | if (NULL != ms->unlock) {
737 | (*ms->unlock)();
738 | }
739 | }
740 | }
741 | if (false == trans->csw_valid) {
742 | scsi_command(ms, trans, EVENT_NEED_STATUS);
743 | trans->csw_valid = true;
744 | }
745 |
746 | left = sizeof(struct usb_msc_csw) - trans->csw_sent;
747 | if (0 < left) {
748 | max_len = MIN(ms->ep_out_size, left);
749 | p = &trans->csw.buf[trans->csw_sent];
750 | len = usbd_ep_write_packet(usbd_dev, ep, p, max_len);
751 | trans->csw_sent += len;
752 | } else if (sizeof(struct usb_msc_csw) == trans->csw_sent) {
753 | /* End of transaction */
754 | trans->lba_start = 0xffffffff;
755 | trans->block_count = 0;
756 | trans->current_block = 0;
757 | trans->cbw_cnt = 0;
758 | trans->bytes_to_read = 0;
759 | trans->bytes_to_write = 0;
760 | trans->byte_count = 0;
761 | trans->csw_sent = 0;
762 | trans->csw_valid = false;
763 | }
764 | }
765 | }
766 |
767 | int msc_started = 0;
768 |
769 | /** @brief Handle various control requests related to the msc storage
770 | * interface.
771 | */
772 | static int msc_control_request(usbd_device *usbd_dev,
773 | struct usb_setup_data *req, uint8_t **buf,
774 | uint16_t *len,
775 | usbd_control_complete_callback *complete)
776 | {
777 | (void)complete;
778 | (void)usbd_dev;
779 |
780 | switch (req->bRequest) {
781 | case USB_MSC_REQ_BULK_ONLY_RESET:
782 | LOG("MSC RESET");
783 | /* Do any special reset code here. */
784 | return USBD_REQ_HANDLED;
785 | case USB_MSC_REQ_GET_MAX_LUN:
786 | LOG("GET MAX LUN");
787 | msc_started = 1;
788 | /* Return the number of LUNs. We use 0. */
789 | *buf[0] = 0;
790 | *len = 1;
791 | return USBD_REQ_HANDLED;
792 | }
793 |
794 | return USBD_REQ_NOTSUPP;
795 | }
796 |
797 | /** @brief Setup the endpoints to be bulk & register the callbacks. */
798 | static void msc_set_config(usbd_device *usbd_dev, uint16_t wValue)
799 | {
800 | usbd_mass_storage *ms = &_mass_storage;
801 |
802 | (void)wValue;
803 |
804 | usbd_ep_setup(usbd_dev, ms->ep_in, USB_ENDPOINT_ATTR_BULK,
805 | ms->ep_in_size, msc_data_tx_cb);
806 | usbd_ep_setup(usbd_dev, ms->ep_out, USB_ENDPOINT_ATTR_BULK,
807 | ms->ep_out_size, msc_data_rx_cb);
808 |
809 | usbd_register_control_callback(
810 | usbd_dev,
811 | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE,
812 | USB_REQ_TYPE_TYPE | USB_REQ_TYPE_RECIPIENT,
813 | msc_control_request);
814 | }
815 |
816 | /** @addtogroup usb_msc */
817 | /** @{ */
818 |
819 | /** @brief Initializes the USB Mass Storage subsystem.
820 |
821 | @note Currently you can only have this profile active.
822 |
823 | @param[in] usbd_dev The USB device to associate the Mass Storage with.
824 | @param[in] ep_in The USB 'IN' endpoint.
825 | @param[in] ep_in_size The maximum endpoint size. Valid values: 8, 16, 32 or 64
826 | @param[in] ep_out The USB 'OUT' endpoint.
827 | @param[in] ep_out_size The maximum endpoint size. Valid values: 8, 16, 32 or 64
828 | @param[in] vendor_id The SCSI vendor ID to return. Maximum used length is 8.
829 | @param[in] product_id The SCSI product ID to return. Maximum used length is 16.
830 | @param[in] product_revision_level The SCSI product revision level to return.
831 | Maximum used length is 4.
832 | @param[in] block_count The number of 512-byte blocks available.
833 | @param[in] read_block The function called when the host requests to read a LBA
834 | block. Must _NOT_ be NULL.
835 | @param[in] write_block The function called when the host requests to write a
836 | LBA block. Must _NOT_ be NULL.
837 |
838 | @return Pointer to the usbd_mass_storage struct.
839 | */
840 | usbd_mass_storage *usb_msc_init(usbd_device *usbd_dev,
841 | uint8_t ep_in, uint8_t ep_in_size,
842 | uint8_t ep_out, uint8_t ep_out_size,
843 | const char *vendor_id,
844 | const char *product_id,
845 | const char *product_revision_level,
846 | const uint32_t block_count,
847 | int (*read_block)(uint32_t lba,
848 | uint8_t *copy_to),
849 | int (*write_block)(uint32_t lba,
850 | const uint8_t *copy_from))
851 | {
852 | _mass_storage.usbd_dev = usbd_dev;
853 | _mass_storage.ep_in = ep_in;
854 | _mass_storage.ep_in_size = ep_in_size;
855 | _mass_storage.ep_out = ep_out;
856 | _mass_storage.ep_out_size = ep_out_size;
857 | _mass_storage.vendor_id = vendor_id;
858 | _mass_storage.product_id = product_id;
859 | _mass_storage.product_revision_level = product_revision_level;
860 | _mass_storage.block_count = block_count - 1;
861 | _mass_storage.read_block = read_block;
862 | _mass_storage.write_block = write_block;
863 | _mass_storage.lock = NULL;
864 | _mass_storage.unlock = NULL;
865 |
866 | _mass_storage.trans.lba_start = 0xffffffff;
867 | _mass_storage.trans.block_count = 0;
868 | _mass_storage.trans.current_block = 0;
869 | _mass_storage.trans.cbw_cnt = 0;
870 | _mass_storage.trans.bytes_to_read = 0;
871 | _mass_storage.trans.bytes_to_write = 0;
872 | _mass_storage.trans.byte_count = 0;
873 | _mass_storage.trans.csw_valid = false;
874 | _mass_storage.trans.csw_sent = 0;
875 |
876 | set_sbc_status_good(&_mass_storage);
877 |
878 | usbd_register_set_config_callback(usbd_dev, msc_set_config);
879 |
880 | return &_mass_storage;
881 | }
882 |
883 | /** @} */
--------------------------------------------------------------------------------
/src/webusb.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #include
20 | #include "webusb.h"
21 |
22 | #include "usb_conf.h"
23 | #include "config.h"
24 |
25 | const struct webusb_platform_descriptor webusb_platform = {
26 | .bLength = WEBUSB_PLATFORM_DESCRIPTOR_SIZE,
27 | .bDescriptorType = USB_DT_DEVICE_CAPABILITY,
28 | .bDevCapabilityType = USB_DC_PLATFORM,
29 | .bReserved = 0,
30 | .platformCapabilityUUID = WEBUSB_UUID,
31 | .bcdVersion = 0x0100,
32 | .bVendorCode = WEBUSB_VENDOR_CODE,
33 | .iLandingPage = 1
34 | };
35 |
--------------------------------------------------------------------------------
/src/webusb.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #ifndef WEBUSB_H_INCLUDED
20 | #define WEBUSB_H_INCLUDED
21 |
22 | #include "webusb_defs.h"
23 |
24 | // Arbitrary
25 | #define WEBUSB_VENDOR_CODE 0x01
26 |
27 | extern const struct webusb_platform_descriptor webusb_platform;
28 | extern void webusb_setup(usbd_device* usbd_dev);
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/src/webusb_defs.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #ifndef WEBUSB_DEFS_H_INCLUDED
20 | #define WEBUSB_DEFS_H_INCLUDED
21 |
22 | #include
23 |
24 | #define WEBUSB_REQ_GET_URL 0x02
25 |
26 | #define WEBUSB_DT_URL 3
27 |
28 | #define WEBUSB_URL_SCHEME_HTTP 0
29 | #define WEBUSB_URL_SCHEME_HTTPS 1
30 |
31 | struct webusb_platform_descriptor {
32 | uint8_t bLength;
33 | uint8_t bDescriptorType;
34 | uint8_t bDevCapabilityType;
35 | uint8_t bReserved;
36 | uint8_t platformCapabilityUUID[16];
37 | uint16_t bcdVersion;
38 | uint8_t bVendorCode;
39 | uint8_t iLandingPage;
40 | } __attribute__((packed));
41 |
42 | #define WEBUSB_PLATFORM_DESCRIPTOR_SIZE sizeof(struct webusb_platform_descriptor)
43 |
44 | #define WEBUSB_UUID {0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47,0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65}
45 |
46 | struct webusb_url_descriptor {
47 | uint8_t bLength;
48 | uint8_t bDescriptorType;
49 | uint8_t bScheme;
50 | char URL[];
51 | } __attribute__((packed));
52 |
53 | #define WEBUSB_DT_URL_DESCRIPTOR_SIZE 3
54 |
55 | #endif
56 |
--------------------------------------------------------------------------------
/src/winusb.c:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #include
20 | #include "winusb.h"
21 |
22 | #include "usb_conf.h"
23 |
24 | static const struct winusb_compatible_id_descriptor winusb_wcid = {
25 | .dwLength = (WINUSB_COMPATIBLE_ID_HEADER_SIZE +
26 | 1*WINUSB_COMPATIBLE_ID_FUNCTION_SECTION_SIZE),
27 | .bcdVersion = 0x0100,
28 | .wIndex = 0x0004,
29 | .bNumSections = 1,
30 | .reserved = { 0, 0, 0, 0, 0, 0, 0 },
31 | .functions = {
32 | {
33 | .bInterfaceNumber = 0,
34 | .reserved0 = { 1 },
35 | .compatibleId = "WINUSB",
36 | .subCompatibleId = "",
37 | .reserved1 = { 0, 0, 0, 0, 0, 0}
38 | },
39 | }
40 | };
41 |
42 | static int winusb_control_vendor_request(usbd_device *usbd_dev,
43 | struct usb_setup_data *req,
44 | uint8_t **buf, uint16_t *len,
45 | usbd_control_complete_callback* complete) {
46 | (void)complete;
47 | (void)usbd_dev;
48 |
49 | if (req->bRequest != WINUSB_MS_VENDOR_CODE) {
50 | return USBD_REQ_NEXT_CALLBACK;
51 | }
52 |
53 | int status = USBD_REQ_NOTSUPP;
54 | if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_DEVICE) &&
55 | (req->wIndex == WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR)) {
56 | *buf = (uint8_t*)(&winusb_wcid);
57 | if (*len > winusb_wcid.dwLength) {
58 | *len = winusb_wcid.dwLength;
59 | }
60 | status = USBD_REQ_HANDLED;
61 | } else if (((req->bmRequestType & USB_REQ_TYPE_RECIPIENT) == USB_REQ_TYPE_INTERFACE) &&
62 | (req->wIndex == WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR)) {
63 | status = USBD_REQ_NOTSUPP;
64 | } else {
65 | status = USBD_REQ_NOTSUPP;
66 | }
67 |
68 | return status;
69 | }
70 |
71 | static void winusb_set_config(usbd_device* usbd_dev, uint16_t wValue) {
72 | (void)wValue;
73 | usbd_register_control_callback(
74 | usbd_dev,
75 | USB_REQ_TYPE_VENDOR,
76 | USB_REQ_TYPE_TYPE,
77 | winusb_control_vendor_request);
78 | }
79 |
80 | void winusb_setup(usbd_device* usbd_dev) {
81 | usbd_register_extra_string(usbd_dev, 0xEE, "MSFT100!");
82 | usbd_register_set_config_callback(usbd_dev, winusb_set_config);
83 |
84 | /* Windows probes the compatible ID before setting the configuration,
85 | so also register the callback now */
86 |
87 | usbd_register_control_callback(
88 | usbd_dev,
89 | USB_REQ_TYPE_VENDOR,
90 | USB_REQ_TYPE_TYPE,
91 | winusb_control_vendor_request);
92 | }
93 |
--------------------------------------------------------------------------------
/src/winusb.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #ifndef WINUSB_H_INCLUDED
20 | #define WINUSB_H_INCLUDED
21 |
22 | #include "winusb_defs.h"
23 |
24 | /* Arbitrary, but must be equivalent to the last character in
25 | the special OS descriptor string */
26 | #define WINUSB_MS_VENDOR_CODE 0x21
27 |
28 | extern void winusb_setup(usbd_device* usbd_dev);
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/src/winusb_defs.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2016, Devan Lai
3 | *
4 | * Permission to use, copy, modify, and/or distribute this software
5 | * for any purpose with or without fee is hereby granted, provided
6 | * that the above copyright notice and this permission notice
7 | * appear in all copies.
8 | *
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
10 | * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
11 | * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
12 | * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
13 | * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14 | * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
15 | * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
16 | * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 | */
18 |
19 | #ifndef WINUSB_DEFS_H_INCLUDED
20 | #define WINUSB_DEFS_H_INCLUDED
21 |
22 | #include
23 |
24 | /* Microsoft OS 1.0 descriptors */
25 |
26 | /* Extended Compat ID OS Feature Descriptor Specification */
27 | #define WINUSB_REQ_GET_COMPATIBLE_ID_FEATURE_DESCRIPTOR 0x04
28 | #define WINUSB_REQ_GET_EXTENDED_PROPERTIES_OS_FEATURE_DESCRIPTOR 0x05
29 |
30 | /* Table 2. Function Section */
31 | struct winusb_compatible_id_function_section {
32 | uint8_t bInterfaceNumber;
33 | uint8_t reserved0[1];
34 | const char compatibleId[8];
35 | const char subCompatibleId[8];
36 | uint8_t reserved1[6];
37 | } __attribute__((packed));
38 |
39 | #define WINUSB_COMPATIBLE_ID_FUNCTION_SECTION_SIZE 24
40 |
41 | /* Table 1. Header Section */
42 | struct winusb_compatible_id_descriptor {
43 | uint32_t dwLength;
44 | uint16_t bcdVersion;
45 | uint16_t wIndex;
46 | uint8_t bNumSections;
47 | uint8_t reserved[7];
48 | struct winusb_compatible_id_function_section functions[];
49 | } __attribute__((packed));
50 |
51 | #define WINUSB_COMPATIBLE_ID_HEADER_SIZE 16
52 |
53 | /* Microsoft OS 2.0 Descriptors Specification */
54 |
55 | /* Table 8. Microsoft OS 2.0 descriptor wIndex values */
56 | #define WINUSB_REQ_MS_OS_20_DESCRIPTOR_INDEX 0x07
57 | #define WINUSB_REQ_MS_OS_20_SET_ALT_ENUMERATION 0x08
58 |
59 | /* Table 9. Microsoft OS 2.0 descriptor wDescriptorType values */
60 | #define WINUSB_DT_MS_OS_20_SET_HEADER_DESCRIPTOR 0x00
61 | #define WINUSB_DT_MS_OS_20_SUBSET_HEADER_CONFIGURATION 0x01
62 | #define WINUSB_DT_MS_OS_20_SUBSET_HEADER_FUNCTION 0x02
63 | #define WINUSB_DT_MS_OS_20_FEATURE_COMPATIBLE_ID 0x03
64 | #define WINUSB_DT_MS_OS_20_FEATURE_REG_PROPERTY 0x04
65 | #define WINUSB_DT_MS_OS_20_FEATURE_MIN_RESUME_TIME 0x05
66 | #define WINUSB_DT_MS_OS_20_FEATURE_MODEL_ID 0x06
67 | #define WINUSB_DT_MS_OS_20_FEATURE_CCGP_DEVICE 0x07
68 |
69 | /* Table 3. Microsoft OS 2.0 descriptor platform capability UUID */
70 | #define WINUSB_OS_20_UUID {0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F}
71 |
72 | /* Table 5. Descriptor set information structure */
73 | struct winusb_descriptor_set_information {
74 | uint32_t dwWindowsVersion;
75 | uint16_t wMSOSDescriptorSetTotalLength;
76 | uint8_t bMS_VendorCode;
77 | uint8_t bAltEnumCode;
78 | } __attribute__((packed));
79 |
80 | /* Table 4. Microsoft OS 2.0 platform capability descriptor header */
81 | struct winusb_platform_descriptor {
82 | uint8_t bLength;
83 | uint8_t bDescriptorType;
84 | uint8_t bDevCapabilityType;
85 | uint8_t bReserved;
86 | uint8_t platformCapabilityUUID[16];
87 | struct winusb_descriptor_set_information descriptor_set_information[];
88 | } __attribute__((packed));
89 |
90 | /* Table 10. Microsoft OS 2.0 descriptor set header */
91 | struct winusb_descriptor_set_header {
92 | uint16_t wLength;
93 | uint16_t wDescriptorType;
94 | uint32_t dwWindowsVersion;
95 | uint16_t wTotalLength;
96 | } __attribute__((packed));
97 |
98 | /* Table 11. Configuration subset header */
99 | struct winusb_configuration_subset_header {
100 | uint16_t wLength;
101 | uint16_t wDescriptorType;
102 | uint8_t bConfigurationValue;
103 | uint8_t bReserved;
104 | uint16_t wTotalLength;
105 | } __attribute__((packed));
106 |
107 | /* Table 12. Function subset header */
108 | struct winusb_function_subset_header {
109 | uint16_t wLength;
110 | uint16_t wDescriptorType;
111 | uint8_t bFirstInterface;
112 | uint8_t bReserved;
113 | uint16_t wSubsetLength;
114 | } __attribute__((packed));
115 |
116 | /* Table 13. Microsoft OS 2.0 compatible ID descriptor */
117 | struct winusb_20_compatible_id_feature_descriptor {
118 | uint16_t wLength;
119 | uint16_t wDescriptorType;
120 | const char compatibleId[8];
121 | const char subCompatibleId[8];;
122 | } __attribute__((packed));
123 |
124 | /* Table 15. wPropertyDataType values for the Microsoft OS 2.0 registry property descriptor */
125 | #define WINUSB_PROP_DATA_TYPE_REG_SZ 1
126 | #define WINUSB_PROP_DATA_TYPE_REG_EXPAND_SZ 2
127 | #define WINUSB_PROP_DATA_TYPE_REG_BINARY 3
128 | #define WINUSB_PROP_DATA_TYPE_REG_DWORD_LITTLE_ENDIAN 4
129 | #define WINUSB_PROP_DATA_TYPE_REG_DWORD_BIG_ENDIAN 5
130 | #define WINUSB_PROP_DATA_TYPE_REG_LINK 6
131 | #define WINUSB_PROP_DATA_TYPE_REG_REG_MULTI_SZ 7
132 |
133 | /* Table 16. Microsoft OS 2.0 minimum USB recovery time descriptor */
134 | struct winusb_minimum_recovery_time_descriptor {
135 | uint16_t wLength;
136 | uint16_t wDescriptorType;
137 | uint8_t bResumeRecoveryTime;
138 | uint8_t bResumeSignalingTime;
139 | } __attribute__((packed));
140 |
141 | /* Table 16. Microsoft OS 2.0 model ID descriptor */
142 | struct winusb_model_id_descriptor {
143 | uint16_t wLength;
144 | uint16_t wDescriptorType;
145 | uint8_t modelId[16];
146 | } __attribute__((packed));
147 |
148 | /* Table 17. Microsoft OS 2.0 CCGP device descriptor */
149 | struct winusb_ccgp_device_descriptor {
150 | uint16_t wLength;
151 | uint16_t wDescriptorType;
152 | } __attribute__((packed));
153 |
154 | #endif
155 |
--------------------------------------------------------------------------------
/util/install-toolchain.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -eo pipefail
3 | URL=https://developer.arm.com/-/media/Files/downloads/gnu-rm/6-2017q2/gcc-arm-none-eabi-6-2017-q2-update-linux.tar.bz2
4 | TOOLCHAIN=gcc-arm-none-eabi-6-2017-q2-update
5 | TOOLCHAINS=$HOME/toolchains
6 | TOOLCHAIN_MISSING=0
7 | GCC=${TOOLCHAINS}/gcc-arm-embedded/bin/arm-none-eabi-gcc
8 | if [[ ! -d "${TOOLCHAINS}/gcc-arm-embedded" ]]; then
9 | TOOLCHAIN_MISSING=1
10 | fi;
11 | if [[ ! -f ${GCC} ]]; then
12 | TOOLCHAIN_MISSING=1
13 | fi;
14 |
15 | if [ $TOOLCHAIN_MISSING -eq 1 ]; then
16 | echo "Installing $TOOLCHAIN from $URL to ${TOOLCHAINS}"
17 | mkdir -p ${TOOLCHAINS}
18 | wget -qO- $URL | tar xj -C ${TOOLCHAINS}
19 | rm -rf ${TOOLCHAINS}/gcc-arm-embedded
20 | ln -s $TOOLCHAIN ${TOOLCHAINS}/gcc-arm-embedded
21 | fi;
22 |
23 | EXISTING_TOOLCHAIN=`readlink -f "${TOOLCHAINS}/gcc-arm-embedded"`
24 | echo "Current toolchain is $EXISTING_TOOLCHAIN"
25 |
26 | if ! ldd ${GCC} >/dev/null; then
27 | echo "${GCC} does not appear to be executable on this machine"
28 | exit 1
29 | fi;
30 |
31 | TOOLCHAIN_VER=`${GCC} --version | head -n 1`
32 | echo "Installed toolchain version is $TOOLCHAIN_VER"
33 |
--------------------------------------------------------------------------------