diff options
author | jaseg <git@jaseg.net> | 2020-01-23 14:38:36 +0100 |
---|---|---|
committer | jaseg <git@jaseg.net> | 2020-01-23 14:38:36 +0100 |
commit | 410e38651052038e34843b17269d61e75720f0ba (patch) | |
tree | 987d1853c55b152d5e1362af4420fa52fcd56a81 /gm_platform/fw | |
parent | 6a49b8399fb156d427b5d15746de877ac933ba3d (diff) | |
download | master-thesis-410e38651052038e34843b17269d61e75720f0ba.tar.gz master-thesis-410e38651052038e34843b17269d61e75720f0ba.tar.bz2 master-thesis-410e38651052038e34843b17269d61e75720f0ba.zip |
board bringup: adc, usart working
Diffstat (limited to 'gm_platform/fw')
26 files changed, 8317 insertions, 0 deletions
diff --git a/gm_platform/fw/Makefile b/gm_platform/fw/Makefile new file mode 100644 index 0000000..ea874eb --- /dev/null +++ b/gm_platform/fw/Makefile @@ -0,0 +1,111 @@ +# Megumin LED display firmware +# Copyright (C) 2018 Sebastian Götte <code@jaseg.net> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +CUBE_PATH ?= $(wildcard ~)/resource/STM32CubeF0 +CMSIS_PATH ?= $(CUBE_PATH)/Drivers/CMSIS +CMSIS_DEV_PATH ?= $(CMSIS_PATH)/Device/ST/STM32F0xx +HAL_PATH ?= $(CUBE_PATH)/Drivers/STM32F0xx_HAL_Driver + +MAC_ADDR ?= 0xdeadbeef + +CC := arm-none-eabi-gcc +LD := arm-none-eabi-ld +OBJCOPY := arm-none-eabi-objcopy +OBJDUMP := arm-none-eabi-objdump +SIZE := arm-none-eabi-size + +CFLAGS = -g -Wall -Wextra -std=gnu11 -O0 -fdump-rtl-expand +CFLAGS += -mlittle-endian -mcpu=cortex-m0 -march=armv6-m -mthumb +#CFLAGS += -ffunction-sections -fdata-sections +LDFLAGS = -nostartfiles +#LDFLAGS += -specs=rdimon.specs -DSEMIHOSTING +LDFLAGS += -Wl,-Map=main.map -nostdlib +#LDFLAGS += -Wl,--gc-sections +LIBS = -lgcc +#LIBS += -lrdimon + +# Technically we're using an STM32F030F4, but apart from the TSSOP20 package that one is largely identical to the +# STM32F030*6 and there is no separate device header provided for it, so we're faking a *6 device here. This is +# even documented in stm32f0xx.h. Thanks ST! +CFLAGS += -DSTM32F030x6 -DHSE_VALUE=8000000 + +LDFLAGS += -Tstm32_flash.ld +CFLAGS += -I$(CMSIS_DEV_PATH)/Include -I$(CMSIS_PATH)/Include -I$(HAL_PATH)/Inc -Iconfig -Wno-unused -I../common +LDFLAGS += -L$(CMSIS_PATH)/Lib/GCC -larm_cortexM0l_math + +################################################### + +.PHONY: program clean + +all: main.elf + +.clang: + echo flags = $(CFLAGS) > .clang + +cmsis_exports.c: $(CMSIS_DEV_PATH)/Include/stm32f030x6.h $(CMSIS_PATH)/Include/core_cm0.h + python3 tools/gen_cmsis_exports.py $^ > $@ + +%.o: %.c + $(CC) -c $(CFLAGS) -o $@ $^ +# $(CC) -E $(CFLAGS) -o $(@:.o=.pp) $^ + +%.o: %.s + $(CC) -c $(CFLAGS) -o $@ $^ +# $(CC) -E $(CFLAGS) -o $(@:.o=.pp) $^ + +%.dot: %.elf + r2 -a arm -qc 'aa;agC' $< 2>/dev/null >$@ + +sources.tar.xz: main.c Makefile + tar -caf $@ $^ + +# don't ask... +sources.tar.xz.zip: sources.tar.xz + zip $@ $^ + +sources.c: sources.tar.xz.zip + xxd -i $< | head -n -1 | sed 's/=/__attribute__((section(".source_tarball"))) =/' > $@ + +main.elf: main.c adc.c serial.c cobs.c startup_stm32f030x6.s system_stm32f0xx.c $(HAL_PATH)/Src/stm32f0xx_ll_utils.c base.c cmsis_exports.c + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + $(OBJCOPY) -O ihex $@ $(@:.elf=.hex) + $(OBJCOPY) -O binary $@ $(@:.elf=.bin) + $(OBJDUMP) -St $@ >$(@:.elf=.lst) + $(SIZE) $@ + +program: main.elf openocd.cfg + openocd -f openocd.cfg -c "program $< verify reset exit" + +8b10b_test_encode: 8b10b_test_encode.c 8b10b.c + gcc -o $@ $^ + +8b10b_test_decode: 8b10b_test_decode.c 8b10b.c + gcc -o $@ $^ + +protocol_test: protocol.c protocol_test.c + gcc -o $@ -O0 -Wall -Wextra -g -I../common $^ + +clean: + rm -f **.o + rm -f main.elf main.hex main.bin main.map main.lst + rm -f **.expand + rm -f cmsis_exports.c + rm -f sources.tar.xz + rm -f sources.tar.xz.zip + rm -f sources.c + rm -f *.dot + rm -f protocol_test + diff --git a/gm_platform/fw/Scope.ipynb b/gm_platform/fw/Scope.ipynb new file mode 100644 index 0000000..1022e56 --- /dev/null +++ b/gm_platform/fw/Scope.ipynb @@ -0,0 +1,906 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib import pyplot as plt\n", + "%matplotlib notebook\n", + "import numpy as np\n", + "import struct\n", + "import math" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ + "def plot_data(offx=0, end=-1, signed=False, channels=1):\n", + " with open('/tmp/scope_dump.bin', 'rb') as f:\n", + " raw_data = f.read()\n", + " data = struct.unpack(f'<{len(raw_data)//2}{\"h\" if signed else \"H\"}', raw_data)\n", + " \n", + " fig, axs = plt.subplots(channels*2, 1, squeeze=False, sharex=True, figsize=(10, 5))\n", + " axs = axs.flatten()\n", + " for i, (ax_t, ax_f) in enumerate(zip(axs[0::2], axs[1::2])):\n", + " le_slice = data[offx:][:end][i::channels]\n", + " ax_t.plot(np.linspace(0, len(le_slice)/1000, len(le_slice)),\n", + " [math.nan if x==-255 else x for x in le_slice])\n", + " ax_t.grid() \n", + " \n", + " ax_f.specgram(le_slice, Fs=1000)\n", + " ax_f.grid()\n", + " \n", + " return data" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('<div/>');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " if (mpl.ratio != 1) {\n", + " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", + " }\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " fig.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n", + " 'ui-helper-clearfix\"/>');\n", + " var titletext = $(\n", + " '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n", + " 'text-align: center; padding: 3px;\"/>');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('<div/>');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('<canvas/>');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var backingStore = this.context.backingStorePixelRatio ||\n", + "\tthis.context.webkitBackingStorePixelRatio ||\n", + "\tthis.context.mozBackingStorePixelRatio ||\n", + "\tthis.context.msBackingStorePixelRatio ||\n", + "\tthis.context.oBackingStorePixelRatio ||\n", + "\tthis.context.backingStorePixelRatio || 1;\n", + "\n", + " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", + "\n", + " var rubberband = $('<canvas/>');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width * mpl.ratio);\n", + " canvas.attr('height', height * mpl.ratio);\n", + " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('<div/>')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('<button/>');\n", + " button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n", + " 'ui-button-icon-only');\n", + " button.attr('role', 'button');\n", + " button.attr('aria-disabled', 'false');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + "\n", + " var icon_img = $('<span/>');\n", + " icon_img.addClass('ui-button-icon-primary ui-icon');\n", + " icon_img.addClass(image);\n", + " icon_img.addClass('ui-corner-all');\n", + "\n", + " var tooltip_span = $('<span/>');\n", + " tooltip_span.addClass('ui-button-text');\n", + " tooltip_span.html(tooltip);\n", + "\n", + " button.append(icon_img);\n", + " button.append(tooltip_span);\n", + "\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " var fmt_picker_span = $('<span/>');\n", + "\n", + " var fmt_picker = $('<select/>');\n", + " fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n", + " fmt_picker_span.append(fmt_picker);\n", + " nav_element.append(fmt_picker_span);\n", + " this.format_dropdown = fmt_picker[0];\n", + "\n", + " for (var ind in mpl.extensions) {\n", + " var fmt = mpl.extensions[ind];\n", + " var option = $(\n", + " '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n", + " fmt_picker.append(option)\n", + " }\n", + "\n", + " // Add hover states to the ui-buttons\n", + " $( \".ui-button\" ).hover(\n", + " function() { $(this).addClass(\"ui-state-hover\");},\n", + " function() { $(this).removeClass(\"ui-state-hover\");}\n", + " );\n", + "\n", + " var status_bar = $('<span class=\"mpl-message\"/>');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "}\n", + "\n", + "mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n", + " // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n", + " // which will in turn request a refresh of the image.\n", + " this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n", + "}\n", + "\n", + "mpl.figure.prototype.send_message = function(type, properties) {\n", + " properties['type'] = type;\n", + " properties['figure_id'] = this.id;\n", + " this.ws.send(JSON.stringify(properties));\n", + "}\n", + "\n", + "mpl.figure.prototype.send_draw_message = function() {\n", + " if (!this.waiting) {\n", + " this.waiting = true;\n", + " this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n", + " }\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " var format_dropdown = fig.format_dropdown;\n", + " var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n", + " fig.ondownload(fig, format);\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype.handle_resize = function(fig, msg) {\n", + " var size = msg['size'];\n", + " if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n", + " fig._resize_canvas(size[0], size[1]);\n", + " fig.send_message(\"refresh\", {});\n", + " };\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n", + " var x0 = msg['x0'] / mpl.ratio;\n", + " var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n", + " var x1 = msg['x1'] / mpl.ratio;\n", + " var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n", + " x0 = Math.floor(x0) + 0.5;\n", + " y0 = Math.floor(y0) + 0.5;\n", + " x1 = Math.floor(x1) + 0.5;\n", + " y1 = Math.floor(y1) + 0.5;\n", + " var min_x = Math.min(x0, x1);\n", + " var min_y = Math.min(y0, y1);\n", + " var width = Math.abs(x1 - x0);\n", + " var height = Math.abs(y1 - y0);\n", + "\n", + " fig.rubberband_context.clearRect(\n", + " 0, 0, fig.canvas.width, fig.canvas.height);\n", + "\n", + " fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n", + " // Updates the figure title.\n", + " fig.header.textContent = msg['label'];\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_cursor = function(fig, msg) {\n", + " var cursor = msg['cursor'];\n", + " switch(cursor)\n", + " {\n", + " case 0:\n", + " cursor = 'pointer';\n", + " break;\n", + " case 1:\n", + " cursor = 'default';\n", + " break;\n", + " case 2:\n", + " cursor = 'crosshair';\n", + " break;\n", + " case 3:\n", + " cursor = 'move';\n", + " break;\n", + " }\n", + " fig.rubberband_canvas.style.cursor = cursor;\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_message = function(fig, msg) {\n", + " fig.message.textContent = msg['message'];\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_draw = function(fig, msg) {\n", + " // Request the server to send over a new figure.\n", + " fig.send_draw_message();\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n", + " fig.image_mode = msg['mode'];\n", + "}\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function() {\n", + " // Called whenever the canvas gets updated.\n", + " this.send_message(\"ack\", {});\n", + "}\n", + "\n", + "// A function to construct a web socket function for onmessage handling.\n", + "// Called in the figure constructor.\n", + "mpl.figure.prototype._make_on_message_function = function(fig) {\n", + " return function socket_on_message(evt) {\n", + " if (evt.data instanceof Blob) {\n", + " /* FIXME: We get \"Resource interpreted as Image but\n", + " * transferred with MIME type text/plain:\" errors on\n", + " * Chrome. But how to set the MIME type? It doesn't seem\n", + " * to be part of the websocket stream */\n", + " evt.data.type = \"image/png\";\n", + "\n", + " /* Free the memory for the previous frames */\n", + " if (fig.imageObj.src) {\n", + " (window.URL || window.webkitURL).revokeObjectURL(\n", + " fig.imageObj.src);\n", + " }\n", + "\n", + " fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n", + " evt.data);\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " }\n", + " else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n", + " fig.imageObj.src = evt.data;\n", + " fig.updated_canvas_event();\n", + " fig.waiting = false;\n", + " return;\n", + " }\n", + "\n", + " var msg = JSON.parse(evt.data);\n", + " var msg_type = msg['type'];\n", + "\n", + " // Call the \"handle_{type}\" callback, which takes\n", + " // the figure and JSON message as its only arguments.\n", + " try {\n", + " var callback = fig[\"handle_\" + msg_type];\n", + " } catch (e) {\n", + " console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n", + " return;\n", + " }\n", + "\n", + " if (callback) {\n", + " try {\n", + " // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n", + " callback(fig, msg);\n", + " } catch (e) {\n", + " console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n", + " }\n", + " }\n", + " };\n", + "}\n", + "\n", + "// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n", + "mpl.findpos = function(e) {\n", + " //this section is from http://www.quirksmode.org/js/events_properties.html\n", + " var targ;\n", + " if (!e)\n", + " e = window.event;\n", + " if (e.target)\n", + " targ = e.target;\n", + " else if (e.srcElement)\n", + " targ = e.srcElement;\n", + " if (targ.nodeType == 3) // defeat Safari bug\n", + " targ = targ.parentNode;\n", + "\n", + " // jQuery normalizes the pageX and pageY\n", + " // pageX,Y are the mouse positions relative to the document\n", + " // offset() returns the position of the element relative to the document\n", + " var x = e.pageX - $(targ).offset().left;\n", + " var y = e.pageY - $(targ).offset().top;\n", + "\n", + " return {\"x\": x, \"y\": y};\n", + "};\n", + "\n", + "/*\n", + " * return a copy of an object with only non-object keys\n", + " * we need this to avoid circular references\n", + " * http://stackoverflow.com/a/24161582/3208463\n", + " */\n", + "function simpleKeys (original) {\n", + " return Object.keys(original).reduce(function (obj, key) {\n", + " if (typeof original[key] !== 'object')\n", + " obj[key] = original[key]\n", + " return obj;\n", + " }, {});\n", + "}\n", + "\n", + "mpl.figure.prototype.mouse_event = function(event, name) {\n", + " var canvas_pos = mpl.findpos(event)\n", + "\n", + " if (name === 'button_press')\n", + " {\n", + " this.canvas.focus();\n", + " this.canvas_div.focus();\n", + " }\n", + "\n", + " var x = canvas_pos.x * mpl.ratio;\n", + " var y = canvas_pos.y * mpl.ratio;\n", + "\n", + " this.send_message(name, {x: x, y: y, button: event.button,\n", + " step: event.step,\n", + " guiEvent: simpleKeys(event)});\n", + "\n", + " /* This prevents the web browser from automatically changing to\n", + " * the text insertion cursor when the button is pressed. We want\n", + " * to control all of the cursor setting manually through the\n", + " * 'cursor' event from matplotlib */\n", + " event.preventDefault();\n", + " return false;\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " // Handle any extra behaviour associated with a key event\n", + "}\n", + "\n", + "mpl.figure.prototype.key_event = function(event, name) {\n", + "\n", + " // Prevent repeat events\n", + " if (name == 'key_press')\n", + " {\n", + " if (event.which === this._key)\n", + " return;\n", + " else\n", + " this._key = event.which;\n", + " }\n", + " if (name == 'key_release')\n", + " this._key = null;\n", + "\n", + " var value = '';\n", + " if (event.ctrlKey && event.which != 17)\n", + " value += \"ctrl+\";\n", + " if (event.altKey && event.which != 18)\n", + " value += \"alt+\";\n", + " if (event.shiftKey && event.which != 16)\n", + " value += \"shift+\";\n", + "\n", + " value += 'k';\n", + " value += event.which.toString();\n", + "\n", + " this._key_event_extra(event, name);\n", + "\n", + " this.send_message(name, {key: value,\n", + " guiEvent: simpleKeys(event)});\n", + " return false;\n", + "}\n", + "\n", + "mpl.figure.prototype.toolbar_button_onclick = function(name) {\n", + " if (name == 'download') {\n", + " this.handle_save(this, null);\n", + " } else {\n", + " this.send_message(\"toolbar_button\", {name: name});\n", + " }\n", + "};\n", + "\n", + "mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n", + " this.message.textContent = tooltip;\n", + "};\n", + "mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n", + "\n", + "mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n", + "\n", + "mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n", + " // Create a \"websocket\"-like object which calls the given IPython comm\n", + " // object with the appropriate methods. Currently this is a non binary\n", + " // socket, so there is still some room for performance tuning.\n", + " var ws = {};\n", + "\n", + " ws.close = function() {\n", + " comm.close()\n", + " };\n", + " ws.send = function(m) {\n", + " //console.log('sending', m);\n", + " comm.send(m);\n", + " };\n", + " // Register the callback with on_msg.\n", + " comm.on_msg(function(msg) {\n", + " //console.log('receiving', msg['content']['data'], msg);\n", + " // Pass the mpl event to the overridden (by mpl) onmessage function.\n", + " ws.onmessage(msg['content']['data'])\n", + " });\n", + " return ws;\n", + "}\n", + "\n", + "mpl.mpl_figure_comm = function(comm, msg) {\n", + " // This is the function which gets called when the mpl process\n", + " // starts-up an IPython Comm through the \"matplotlib\" channel.\n", + "\n", + " var id = msg.content.data.id;\n", + " // Get hold of the div created by the display call when the Comm\n", + " // socket was opened in Python.\n", + " var element = $(\"#\" + id);\n", + " var ws_proxy = comm_websocket_adapter(comm)\n", + "\n", + " function ondownload(figure, format) {\n", + " window.open(figure.imageObj.src);\n", + " }\n", + "\n", + " var fig = new mpl.figure(id, ws_proxy,\n", + " ondownload,\n", + " element.get(0));\n", + "\n", + " // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n", + " // web socket which is closed, not our websocket->open comm proxy.\n", + " ws_proxy.onopen();\n", + "\n", + " fig.parent_element = element.get(0);\n", + " fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n", + " if (!fig.cell_info) {\n", + " console.error(\"Failed to find cell for figure\", id, fig);\n", + " return;\n", + " }\n", + "\n", + " var output_index = fig.cell_info[2]\n", + " var cell = fig.cell_info[0];\n", + "\n", + "};\n", + "\n", + "mpl.figure.prototype.handle_close = function(fig, msg) {\n", + " var width = fig.canvas.width/mpl.ratio\n", + " fig.root.unbind('remove')\n", + "\n", + " // Update the output cell to use the data from the current canvas.\n", + " fig.push_to_output();\n", + " var dataURL = fig.canvas.toDataURL();\n", + " // Re-enable the keyboard manager in IPython - without this line, in FF,\n", + " // the notebook keyboard shortcuts fail.\n", + " IPython.keyboard_manager.enable()\n", + " $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n", + " fig.close_ws(fig, msg);\n", + "}\n", + "\n", + "mpl.figure.prototype.close_ws = function(fig, msg){\n", + " fig.send_message('closing', msg);\n", + " // fig.ws.close()\n", + "}\n", + "\n", + "mpl.figure.prototype.push_to_output = function(remove_interactive) {\n", + " // Turn the data on the canvas into data in the output cell.\n", + " var width = this.canvas.width/mpl.ratio\n", + " var dataURL = this.canvas.toDataURL();\n", + " this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n", + "}\n", + "\n", + "mpl.figure.prototype.updated_canvas_event = function() {\n", + " // Tell IPython that the notebook contents must change.\n", + " IPython.notebook.set_dirty(true);\n", + " this.send_message(\"ack\", {});\n", + " var fig = this;\n", + " // Wait a second, then push the new image to the DOM so\n", + " // that it is saved nicely (might be nice to debounce this).\n", + " setTimeout(function () { fig.push_to_output() }, 1000);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('<div/>')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items){\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) { continue; };\n", + "\n", + " var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n", + " var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " event.shiftKey = false;\n", + " // Send a \"J\" for go to next cell\n", + " event.which = 74;\n", + " event.keyCode = 74;\n", + " manager.command_mode();\n", + " manager.handle_keydown(event);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i<ncells; i++) {\n", + " var cell = cells[i];\n", + " if (cell.cell_type === 'code'){\n", + " for (var j=0; j<cell.output_area.outputs.length; j++) {\n", + " var data = cell.output_area.outputs[j];\n", + " if (data.data) {\n", + " // IPython >= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "<IPython.core.display.Javascript object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA+gAAAH0CAYAAACuKActAAAgAElEQVR4nOx9Z5Ae5ZW1ar9al8tbtmtd3q0t11Y1GZtgMBkTbIEBY0wyBkeCwQZMMGAwrSyhHJAEEgqghAISSqDwajRKo5xzHGmUNRKSUBplTUsz9/vR73n69jPd07cH70zLc09VF9/nndb7vt1PP33Pveee24AUCoVCoVAoFAqFQqFQ1Dka1PUXUCgUCoVCoVAoFAqFQqEEXaFQKBQKhUKhUCgUikxACbpCoVAoFAqFQqFQKBQZgBJ0hUKhUCgUCoVCoVAoMgAl6AqFQqFQKBQKhUKhUGQAStAVCoVCoVAoFAqFQqHIAJSgKxQKhUKhUCgUCoVCkQEoQVcoFAqFQqFQKBQKhSIDUIKuUCgUCoVCoVAoFApFBqAEXaFQKBQKhUKhUCgUigxACbpCoVAoFAqFQqFQKBQZgBJ0hUKhUCgUCoVCoVAoMgAl6AqFQqFQKBQKhUKhUGQAStAVCoVCoVAoFAqFQqHIAJSgKxQKhUKhUCgUCoVCkQEoQVcoFAqFQqFQKBQKhSIDUIKuUCgUCoVCoVAoFApFBqAEXaFQKBQKhUKhUCgUigxACbpCoVAoFAqFQqFQKBQZgBJ0hUKhUCgUCoVCoVAoMgAl6AqFQqFQKBQKhUKhUGQAStAVCoVCoVAoFAqFQqHIAJSgKxQKhUKhUCgUCoVCkQEoQVcoFAqFQqFQKBQKhSIDUIKuUCgUCoVCoVAoFApFBqAEXaFQKBQKhUKhUCgUigxACbpCoVAoFAqFQqFQKBQZgBJ0hUKhUCgUCoVCoVAoMgAl6AqFQqFQKBQKhUKhUGQAStAVCoVCoVAoFAqFQqHIAJSgKxQKhUKhUCgUCoVCkQEoQVcoFAqFQqFQKBQKhSIDUIKuUCgUCoVCoVAoFApFBqAEXaFQKBQKhUKhUCgUigxACbpCoVAoFAqFQqFQKBQZgBJ0hUKhUCgUCoVCoVAoMgAl6AqFQqFQKBQKhUKhUGQAStAVCoVCoVAoFAqFQqHIAJSgKxQKhUKhUCgUCoVCkQEoQVcoFAqFQqFQKBQKhSIDUIKuUCgUCoVCoVAoFApFBqAEXaFQKBQKhUKhUCgUigxACbpCoVAoFAqFQqFQKBQZgBJ0hUKhUCgUCoVCoVAoMgAl6AqFQqFQKBQKhUKhUGQAStAVCoVCoVAoFAqFQqHIAJSgKxQKhUKhUCgUCoVCkQEoQVcoFAqFQqFQKBQKhSIDUIKuUCgUCoVCoVAoFApFBqAEXaFQKBQKhUKhUCgUigxACbpCoVAoFAqFQqFQKBQZgBJ0hUKhUCgUCoVCoVAoMgAl6AqFQqFQKBQKhUKhUGQAStAVCoVCoVAoFAqFQqHIAJSgKxQKhUKhUCgUCoVCkQEoQVcoFAqFQqFQKBQKhSIDUIKuUCgUCoVCoVAoFApFBqAEXaFQKBQKhUKhUCgUigxACXo9Q0VFBZWWllJZWRkdPXpUDz300EMPPfTQQw899KinR1lZGZWWllJFRUVd0xRFHkrQ6xlKS0upQYMGeuihhx566KGHHnrooYce1KBBAyotLa1rmqLIQwl6PUNZWZl5COs6Y3fw4EEaPnw4HTx4sM6/ix7ZPnSt6CE5dJ3oITl0neghOXSd6CE9zve1guJdWVlZXdMURR5K0OsZjh49Sg0aNKCjR4/W9Vchz/No3Lhx5HleXX8VRcaha0Uhga4ThQS6ThQS6DpRSHG+r5UscQOFDyXo9QxZegjP9w1NUXvQtaKQQNeJQgJdJwoJdJ0opDjf10qWuIHChxL0eoYsPYTn+4amqD3oWlFIoOtEIYGuE4UEuk4UUpzvayVL3EDhQwl6PUOWHsLzfUNT1B50rSgk0HWikEDXiUICXScKKc73tZIlbqDwoQS9niFLD2FdbWjeufRjJCorK2t03tlzFVRRUZn6vDNnz9Gx0+mvS02+o42z5yqo7GT6z/6//M5Ra+XYaY/OnD2X+vOOnCyncynvSWVlJR06UU6VlenOO1dRmfqziPxrUpPPOnD8DJ0sP5v68/CZaVF20qOztfRceOcqEr+jvU5q+txW5K/l8TPpriXuW9rPrOl5RDXfY2qyxnBeGlRW+teytvazmu4nX2XvrMm1/Gfs1bWB2vyedXFNqvvM8510KWoP5/tayRI3UPhQgl7PkKWHsC42tC6FG+nyZgW0ad+xVOe9MGQZXdd6KpWdkn/XcxWVdG+32fTz9+akCt4OnyinH7WeShc2ytG4lbvF563dXUaXNyug7tM2ic+xcfZcBd3ddRY5bo4+KNosPu/A8TN0zTtT6KLGk2jSmi/E563adYQua1qQ+Fn2Whm/ag9d2ChH174zhQ6dKBd/3nvTSshxc3RPt1mpiPPfRqwgx83R80OWis+pqKikB3rMoXu7zU71WcdOe3RD22n0wpBl4nMqK/3PctwcXdqkgJZsPyQ+l4io6edr6KqWhfRF2SnxOf3mbCXHzdEdnYqo/Kw8sD7tnaMfd5hBf+i3KPVnOW6OWo5fF/t39jppNHYNXdki3e8iInqi7wJy3Bxd3HgSzdr0pegc/C7HzdEVzSfT1i+Pi87bdegkXdmikBw3Rze1m0YnUiQF8Lw+9MG8VHsMntc3R60Sn0NEtLrUf157zZTvDc8OWkKOm6OLGk+iyWvle8OKnYfpsqYF1HvmFvE5+4+dpqtbFtLfR1b/u+x1smLnYbq48aRUex5Qdsp/Xl8cKn9eu0/bRJc2LaB1e7LtmDx1/T66tEkBjV3+fz96CZ81elntjXmav/kAXdq0gIYs2B75fz/fSZei9nC+r5UscQOFDyXo9QxZegjrYkNDkP/0wMU1Ou+TRTvF5+w/dtqcl4ZELt1+yJzXaOxq8XlPDVhszqsp9pYF3/nJAfJrNG/zAXNeqwnxBMrGwx/ME33nqsRrtTlv4daD4s97rPd8c96B42fE5+GcNNf24PEz5pzSwyfF541buTv1Z50sPxv6jh/OlpMaouD3dSncKD7n6YHBett1SP77ior3p/59/LdVd569TvD3rSeuF38WEdEFjYLP6jpVlvCav+VA6Du+JSS/70xYHzpv6vp94u+5ef9xc95pT64m6TZ1U432iod6zk193lX55EPa+/DLHuk/q8+sLTXaT+5/b06N985hi3bUeD0/3mdB6s+rTdRk36spLmo8qdY+C7i6ZWG1n3m+ky5F7eF8XytZ4gYKH0rQ6xmy9BDWJUF/6IN5NTovTYXl0Ilyc97m/bJqGhHR4m0BQf/LYHnF9pXhK75ygLP1yyDg/3Wf+eLzpq7fZ85zx8iTCqj6pg2o/zJ4qTmvqHi/+PMavjszNak8V1FZo0B18/5j5pw0lbLCdXtTk67jZ8IEPa2KAuf1mF4iPudBRtbSrO/xq/aY86RV369K0N8YuVL8/ezPa5uTkcp1e8pC5zX9fI3ovO7TNoXOm1Miq9gThdfY4RRJwHaTNtQaQb+i+WSWcJRdEyKi+7rPTv1ZIxbvFK0te5080kuWKIyCNCnAgb+/u+us1J9Xm6hNgn7tO1NqnaDzRFwUznfSpag9nO9rJUvcQOFDCXo9Q5Yewrok6Hd0KqrReWkqQLyCmkZyvGjrQXPer3rLSXLzcWu/coDDScYDPeaIz+Ok628jVojPqylB/xWrhKeR1P+wVRAEStscDrD76Lg5cc/1QnYfZwtl0kRE0zcEyY49R2TS7GOnvdB3bF+wQfx5Z86eM+f1m7NVfB7k3I6bo/V75PvJJ4sCEiX1EPiqBP2ZFIqZyspwQkZKtDftOxY6T0rsP56/vcYEff2eo6nXCpHf0lBbBP37zQKC/vqn8kRJTQj65LVBcqu6VgF7nfz2w4U13ju7FG6sMUG/rvXU1J9Xm6hNgt6wy8xa+ywg6fed76RLUXs439dKlriBwocS9HqGLD2EdUnQr2pZWKPz0lTivjwWELvJa/eKz1uwJSB2P+0yU3xeVyZbrYkxGVFYXt/wXflnf7okIF1/TlH15wS9OqMre638lAVz0p5F71xFKCBbueuI6DybeEnNriat+cKc8/kKuZfAxNVBsmPtblnlvexUmKA3H7dW/HlflJ0y5w2at0183uXNClJfSyKiD2dvSX0tvypBfziFYsZWTEif+eK9R0PndZ0iaxfgLQ2Om6PCdfK9YtmO4HlNo2L4+8hV5rw0ves1IeiXNQ3WSRoPB07Qpd9x5sagfaI6hYy9Tni7Rlq0HL8u9ffE31/YqPbIaE1QmwT90a+gYqgplKAr/lk439dKlriBwocS9HqGLD2EdUnQ0wYBOOdPg5aIz9l/NOjnTtO7Pp/1c1+dIpHQf+42c97BFP3VHHNKvjT/xi3tp4vPGzQv+Ow/9pebf/3i/YCgHzkZL9G11wrvHRyycIfos7gngOPmaP6WA6LzeMLEcXO0/9hp0XlDFga9qf3nyonvyKW7zHlSg7IjJ8tD3zGN+dfa3YFqos8sWe+63fO+eJtcIcIrjtJ1ahP0OCIUR9B/0lmumLETOVLzL17NdtwcvSsk6BOY+iRtMmduSbBXSJM5RER/HbbMnHeqXN67XhOCfmmTgKCn8bXgBF1qzlnECHp1SSN7nbwwZFnq3wXwZIfULLE2ie9XQW1+T5gJKkFXnI8439dKlriBwocS9HqGLD2E5yNBf6SXvBLHDdd6zpD39vKg23Fz4tEznCSXpHSpB3j/8zXvTBGf12vmZnNeGln+nZ2LzHlbqnG95mvFJlBSQzS7wjmjWGbGlVv9Rei8HQdPiM6DY7zj5qhzYbHoHCKiwQsCyfNnK2TqAO534Lg5eumT5eLPm7UpSMpIDdF2HToZ+ry5JbJkBxFR488CebXUXZ0nZBw3XhofR9B/2Eq+lrnk33HlhpI80eG48nYYu4I+fLE8mTeFPa9pkiS8YpzGwLImBP1iZv6Vxtfi9k5BC8W2A7JnbkZx0B5S3fNtr5PXRtTcv+P5IYEfhnQs3/lA0O1WjzSJnJqAJzpqMj6zJsDnXd6sIPL/fr6TLkXt4XxfK1niBgofStDrGbL0EJ6PBD2N5HzPkUA6nMbZfDYjTI6bo/1HZRXbAayCnsbZnIOThUubRgctUeg6JaiK3v+evHedOzxX16fP1wpXJjhujt6bJkt+cGWC4+Zo4uo9ovOGLAj3CBfvlT07LZgnQBo3fm46Je0Jt/vk0yg9PltRas5rN0nWu75q15HQ503fIHce59VKabLjJyyR47jxaos4gp7meT/thQn6431lTttrSsMEvfFnst71z1eECXoatQV/XqVqC6Lw9IQ0EwZqQtAvZEZcaXwtuLncsh2y5MM0ZlY5aumu2L+z18nbo1en/l3A7z4K+telyY5Lmew/q7B9LdKsk5qAtwqkHYtYE1SwVpbr20yL/JvznXQpag/n+1rJEjdQ+FCCXs+QpYfQ8zwaMmocvfrJcnpqwOJUo6E27TtGLwxZRk8PXEzjV8mIFhHRVawSl4bE8kBF2utZejhcZZQGb7yP0nFztOEL2b3is6J/8b48EOYYzlyQHVfey95mYjAqSprEsCuV1fXp85ffhi/ClXCpIZotJa4ugOewXbaX7zwsOu/lT5abc9K48fMRWJ0myyrvtnz/tx8uFJ1XUVEZIgtSQzQ+Ks1xc1QgNOrbeTD8TEiVHpxQVhfAV0fQ15TKJOC2fP/BnnNF5620khZSQ7Qxy0pD50knRXCFjv/8yO6B7Ta/eb/sHtj7UnWeEYBdhZX6WthJkinCvnyuKKhu/7LXCU+mpZnxzsfcOW6O9pbJkqk3tZtmzpm3Wa4+Gb9qDz09cDG9MGSZ2OSSiOij2VvpqQGL6bURK+jLY7K2kh0HT4R+2+pSmc/E0dMevTlqFT01YLFYkUMUvgdpPDRW7DxMfx68lP40aEmqiR5cdRTXAhNFuj6ev53+OmwZvTVqldiYsbKykjpOLqanBiymf4xeRSfLZUoLxT8Xm/cfoxeHLqOW49eJ9i8iP/n99ujV9NIny6n3zPgY1V4r+KynBy6mcSvlbUt1hSxxA4UPJej1DFl6CD3Pozf7jjcvyQsayWV0/GV+W8cZ4s/k5mJ/6CfvleaBSsvxsmq4LQOWSldt8iOVD3PzLceVV945eBXeceWSzSZMtnxTu+hqhA1uoue4ORq2KL6XnL/8uDt6mmBuKOsJd9wcDV6wXXReqwnrQudJA+o/9l9kznksheyfj8B6e7Ss8r7PUhVIxwjayQ6pIZpd9ZUGIHayQ9o3/ZsPF4TOi2uHsIMkPlv51eGy6QL2yDrpKKzlOw+HzpMaoo1ingOOK2+H+BPr2XXcHI1dLmuHaDR2deg8KfHi5zhu9S7pQIVluCf1tbBVMtK9k7u4O26OVsX0odvrhD9zjisfWccTk46bo50HZVVm3l8vTaYRhWX/TYQKjdPeudA4Mem+t7o0nHCSTqIYbyVCdwtJbLPPg3f6pU3k6q2XWCI0zfjUEmb+eXun6BgiiqDz3/b7frJ7ZycmpQknxT8XPG6UJmzfGLkydO/i/DDstfLOhGBvSOPnU1fIEjdQ+FCCXs+QpYfQ8zx6rff40OZ3QGgaxYPMNP2l93SbZc67r/ts8Xm8j/KlYbL+XrsCIVUI8DFbacgPl0Y7brrZ28AHRZtD/4bUEO2NT4OXmNTYziaV1c3g5i+/+VvCUvW3hIZogy2putQQjUsvHTdH09bL5Nx/6BcQ9IYpWiP4CKznPpaRPO7E7rg5uqebjFTaUvW/DpMZotlV35FCNUKnycWh86RqhCf6hgl6HLG3g6Tr20xNTYSOWtLeH3eQJQC5o7rjyg3RRi4JE3RpO0zDd2eGzqsuwcVhB5xSJZFN0CV79VnLL0Lqa2GvZ6mqoGBN2C8iLrlpr5N3WYuO48ol1ny0pePK1Qh8eoVUoUEUrrxLVTm2VF16LVdYCSfpJJLR1t4gnfDAk7yOK1NoEBH9eXDgAZBm8ghP9MYlle11YitC4qTxNjbvD08CGSOcPKL45+LFoUF71SLhvve49e7ZF1P4sNcKf49f2SLd1KC6QJa4gcKHEvR6hiw9hJ7n0d8sgl7daBwO3jOYplf67q6zUr9cicJ9lL/5UNaTuu1AmKBLe6Wnrg8T9IHC0VfcqM1x083eBjoXhgmUtCLE+4ovaTJJdI4dhFenTOAvv3lWL7nUEI2b6DlujroJ5Zd2EC5tqeC9qWmSSNws6VGhKeHuI+FrGVcRsmFXfaWGaHbVd6jQSb99QbhSuWCLMEjqEw6S4vwK7CDpR60Dgn5vN1lCruxkmND8SDiresn2MEGXGqKNsNpKpH4Fv+o9P3Se1K+AG6I5bo6KNspkwTZBl+zV5WfDBF26V9vr+Z0JMsM929BxakwyzV4nvK3EcXO0tRrDSg4ehDuuXBFy/3sBQf+ZUKFBRHRD24CgS8047RGMXQpl0wWW7QjvDdLpAiOtvUFqxtlobPhaStV0z30cKEluTVGp5GMw4xJH9jqxRzBK91l7VKd0v1T8c8HJ9pwSWXzETSAdN0fbYwwr7bXCzVAvajwp1TjLukCWuIHChxL0eoYsPYSe59GrvcIEXdpX99aoVaHzpL3SvOp0UeNJ4iw9/yxpdXLLl+H+RGmvdKHVRykd12RXv9OMawK4LMtx5YZoTw1YHDpP4jxvB+HVSZD5y4+PgnPcHD0rNESz5ftSQzQ7CB+5RFYttmXZUjd+PgJLOh7Mbqe4vo2MVNpV3yeEhmh21XeA0NjMlhJLjc0es8ho3Hl2kHTNO1PYNZEl5A5bjvhxDs82FlmtF1JDtE8WhQn630bIpPicmDhu9QoUjleHhwn6JKF/gE3QJXu13Usu3avt9fya8JrYPhNx6iN7nXS1KuhSot3YqvpKFSFc4i5VaBCFFSFSrw97BKM02bHUSjhJR4V+uiS8nqVeH+6YcOuFdAQjb/VIM3mEj8H8QfPJkX9jrxN7gog06WdPEPlotiyZpvjnghdopEo4uyVo/Z7omMheK/Z5tTWZoKbIEjdQ+FCCXs+QpYfQ8zx6xSLoUjkcrzI6rrxXmvegO271s7eBqrI2GfmxZW3SXunJa8NVIKkbdI/pJaHz0rhBA/ZLRRpw2hXOo6eTnUztILw6TwD+8rPNqqTSZW6i57hyQzS7sjNIqGiwpXFST4Bn2Aisq4TtAnaPY1zAaWPxtnAQLpXb2maC0naB1lbPblyF08ajvcImcXGGaHaQxMezSRNyBy1HfMeVyW0XbAkTdKnc1vZG+LNQuvymlaTsKDQU5D27jpuj0UK5rX1NJHv1qfKqBF2yV9vtQX/sL/MLsUfWfbokmlTa66RLYZigL61mogSHvV9K2wXu7RYQ9OuECg2isCJE2kpkj2BsNFa279kJJ+n7xN4b+gr3hn+MDq9nqWs8Hxl4WQo1HR+DeXHjaNWXvU5sY1Npz/v6PWGC/r4wmab454I/P9LEZEerLWvZjuiYqLrJEI6bo7KT2XZ3zxI3UPhQgl7PkKWH0PM8eumDMEGXSl5f/zTcRyntlb7TGtdU3extwJa1SQN9W9Ym7ZW2+yhfGCLrC+YBh+Omm70N2PLX+UJDtF/2mBu+HwIyagfhP69mPBt/+dkmeg8LgyTbRO/vI2X3w67sVOfkymFXfaVu/Ha/dfnZ5Mr7dqud4oJGOZGkzjbck8pthy0Kk0ppwGkb7uVWy4Ik28U9bj68HSTxMX6OK0vI2eaFjpsTuS7bY/ykclt7jJ+UjLbNhZMdUvNKrtBw3BwNEcpt7Wsi2atPWIZ7jpsTuYjb7UHSqRS2eWFce5C9TmxvBGl7kE0qpef9jFXyvt9MlkwjIvphqymhz5Oocuz1LFUj2AmnnjNkz7i9N7QXKpXshJN0wsOTlnpLqqZrYbUuRb3T7XViK0KkyeG1u8OTEzoUpH83K74azlVUhswSpQpDu3VQ6mthr+faGB34VZAlbqDwoQS9niFLD6HnefRXi6BL+9X+ZhFJ6Txl7oLruNXP3jbf05K1Oa7M5deWtUl7pe0+ysf7yGTHdh9lmtnbwF8Gh/utpDKwuyzDqrg+LQ47CL+xbbwEmb/8bBM9qczQNtGTGqLZQXhXYcuBXfWVur8/2DOc7IgzpeHYmm+n4AHIaS9ZUmcb7knltkOsqq+0r9U23Isj2jYwfxtmjXGGaHaQxGdpO64sIWc7iDuuzBBtbsmB0HeUym0/nr89dJ60t9iu+kod/7lfhOPKzSvtayLZq7lBGX6fxNfCbg+SuiCPXR42KIsbmWavkw4FYYJeKHTZtoPwmu6X0v5UPibUcWWJUHs9S6cL2Akn6chHO+H0pjAxbZsXxjnw2+BmnI4rmy5AFB6DGbdf2uvEVoRIXdxtR3xpMk3xz4OtjJK2qtkEXeprYa9nqa9FXSFL3EDhQwl6PUOWHkLP8+jFnmGCLq2ovWL1UUp7pX/cwSfoGL8kcaa1jY4cV+bWa8vapL3Sdh+lVCqLPkr8tjSztwE+GsxxczRBaIiG64pDUi22Zwhf0iTeSIW//GwTvTs6yfq00aMPEvuM0BDNDsLb5mQ9nHbVV2oux6trjitz4weh4RVjSRIJpBLXRCq3BanEIe3n56OUHDdegmwDCg1UEOMM0ewg6fvNJoeeicXbkhNymC5wceNJdHkzf0a8xBBt9qYvQ99RKrcdmDcvxHn3V6Mk4bCrvtIxcnC9xj2Xmlfae6Bkr+YGZWg32Lg3ee8ssdRHlzYpEJFYe7pAnH+HvU7aW94I0uqaHYRLZbO2A7/UEO1KSxEi2Wf3loUJulShYXt9SKcL2HuDdJ9949OaTRfgZpyOK1NoEBH99sPweVHjs+x1YitCpCaeK61pGf8YLUtaAF+UnYrtfa6PKNl3TGwoDNiKRqlyyPb2kfpa2CpPqa9FXSFL3EDhQwl6PUOWHkLP8+iFnhNCm5jUUMbuo5T2St/Sfjo5bo5ubuf/VzJfl8varm8zTRzor9sTlrVJ5XDoo8RnXSusxMGBHb9N6iLN8es+YVm2NMvMe7scN75PiwNB+A9YlTOud52//GCih+qo1Pyr54ySEImVGqIhCMfnSecPo+oLkvfx/O2i827rGE52xEnqOOB3cO07U+jSpv7nSeYPg1TimkjltgMtR3xpRcgepTREOJMZrtdIBMUZotlBEq4FxlNJEnKYLnBpkwKzriWGaEV5bwSerJLIbeGNgPOk5l921Vc6kg/mcrjnUvNKm6BL9mpuuHdrfu9dIdirN+6tujdIetft6QKtJ0Yn0+x1Ys8zlxqi2UG4lNjbXihSQzRcD+wpkhakPZYZ52NChcasTWGC7o6RKTSwN1yWf/akfdpVpgsUy6YL2GacNZlFH0fs7XVij6yTjmq1p2W8LFTTAThP2pf/rwye9EvjjF5TTwXb22dETMxorxVb5SlRa9YlssQNFD6UoNczZOkh9DyPnu8RJuiDhQG73Ucp7ZVGoI4KhsTwi8va7ujk97BLRnTYfWfSQAV9lPgsqeEXzEzw29LM1wVQ9b2kyaRUBArSS8hY529Jvh8Iwq9rPdVU8+Ikm/zlBxO96/LkSWqk9n7+RYtRRdLedQThIGvS6geqvnBelhqpIcGCqu/0DcmyWVQHrms91VTZJG0GMNxDMujCRjnRd+xvOeJL2ylswz3paDAE01jbcW0GdpCEdYzzJAQK0wUua1pg7sWa0uTqx4zifaHPclxZZfSj2T5Bh+xZ2rtuV32fEs5dh+s11qXU1Rv7EQ7JqCguK8V1kVRGN3xxNPQdpSTWni4QZ7BprxN7eoU0eLeDcGlC0/ZCkRIvEHPsRRISW3o4bCAp7ecvssw4pdMFsDfgO0pJbE2nC9hmnBKFBlFVFUNUQtNeJ/bIOumUDXtaxnMfy9R0RGEPHGnS4l8ZW1n7yzGBGS1gK0KkXjK2t4/U18JWedZk7G1tIkvcQOFDCXo9Q5YeQs/z6C8WQZc6vtp9lNLeP5AzBPyScSdc1oYxHZL+S7vvTNorjT5KfJZ0rjhmTOO3SQMjDvQ/g3BLCXWqlXgAACAASURBVBSqy6jKzRTMVkYLwA1tp5lqS5xsjb/8ML8WFUeplBg9+vAhkEqJEYSDrL3+6UrReb94P1z1lRqpYY2iWhbnWM4Bv4Pr20wzo8UkJksgldyb4azAeAqkEscbI2XXxHa2jesRtgHXa6ztOJMlO0hCkgMVeAmBwnSB7zebbEjpsh3J1Y9p+dYLPuNa4tzbN++NgPUinRIBkzisy999JFPoYCQi1mWzz2XTJfD3WCuS0XowKLugkW8CKQ1Ukdy8se00cw/3liX3W9sz5eOeVXud2N4IUkM0OwiXymZtLxSpIRoUIbjnkl55e1pGQ6FCw/b6kE4XgCIE3/EuYYuW3RMunS5gq74kCg2iqiqGbREJTXud2CPrqvNN4VhijayTPqtE4SSXJPH9rw6uCJF6DxFVVYRIW3tsb58PimS+FrbKU6LeqktkiRsofChBr2fI0kPoeR49ZxH0blM3ic61zcykvdKoyDyUrxRLCAKXtSGIlgRGdt/Z7Z1kBlyj832U+CzHlUm5MGMav+1uoSM3xwM95hjSnIZAodcXldgpguuDIPymdtNMQiDOxIu//Cau9nv0UQGROpajR/+ebrNSXR8E4ah6SeWJICSojEqN1LBGr80TbcnaRrLjxrbTzL2T9CyCVPK+d4ljeV/LcE96Td6y+vm7T5M97/h+WNtthNJlKDNg2CchUBhZd0XzySZJJgmMp+RbL7j3gGS6RO+Z/rX8Vd71X6oIwcg6rEupmSR8JhrmCYpU/QCJOu6FRBECg7KLGk8y906STF1T6u8Nt7SfnsoHwJ4pHzcBw14ntqO3dAKGHYRLK++2Z8fqUpkhGhQhuOcSHwB7WobUcM/2+pD2rmNaBr7jncIq80vDwtdSmuz4lTUtQ0pibRVDVOXdXif2yDrps2rLqx8R9q4Thf0YZmW8Clsb4AknaWsjUVVFiPQZR9yAQ+prYas8pe0vdYUscQOFDyXo9QxZegg9z6Nn3w8TdKnZ1HMfhwl62l5pzO2WVDW5rO2RfKAvCYzsvjNpZWxkvo/yEeYCLqlqoo8Sv00qv+MAqUTlUEqgUNlBZWji6mRSiSD81vbTDSmNMz3iLz/06PMEhmTcEFyv0RsuNZdD4AhiIh17h2ovvqd0bYOYowIlcTpHsuPmdtMNkZIE/SCV3DleMooMpBKH1JDw7yPDBF3qDI0kB9Z2XM87XyeVlYE0FEZSEgKFkXVXtSg0906iCJm8dq8h2lCESKTLMCGCG7VUEYKRdViX0qAfn4P1KXXZxnrEWpHsnTAou6TJJHPvJNLlVfnk5o87zDCqnKgKpw17pvyTMbJ/O5i2zQulhmh2EC6VzeIZxSE1RIOaAPc8zrCKw56W8cNWMk8TeH3gkE4XwLQMfEfpZIgXh9ZsusAj1rQMSUsQUVWvj6g2FnudHLCcwOPmp9uwR9alUbfxUZhZr8LWBpBAdVy5cpKoqiJEavZqT8uQ+lrYKk+pr0VdIUvcQOFDCXotoXfv3nT11VfTN7/5TfrmN79Jt9xyCxUUhAOxBQsWUMOGDekb3/gGffvb36af/OQndOpU0BflOA41aNAgdLium+p7ZOkh9DyP/mQRdKnc8tl8HyUOSS85ERn5L4LUuGwoB5e1YUa1JDCy+86uEPaSf7pkZ+izHFc2Mgt9lPht0sCIA1Ji/FdKoNB7jur02OXJpHIlC8IRsMaN1uEvP/To88qJZLQOevRxXW9uJ6skIXAEWZP2D+Ja4HtKjdTgdo0kyUiBGRdPdgSy7OTqAvr5f9V7Pl2Y4APAAVIJwvC00KkZ/fw4L64SbgPVXqztOKM+vk4qWO8m+q4lBAo9jle3LDTBv0QRUpBvvfh1n/lGESIZrQPzQpi3SRUhkGVD9fLLHjLPCbhXI1ElnYsNZQZ6fiWKEMhRL21aYO6dpJKE5OZtHWeYhJVEBm6P+IpTFdjBNMwLsY9JVQXPDwkniqWyWSQ7cBQJEkBEgSIEe5HEqM8eWXepMAGE9YxD2hKEsVRYl1IZuH0tpcnhh6xpGZLkMFFVFUNUG4u9TvYfqzqCUZIcnmeNrJOqCojItHQ5rnws5b8ytrOEk7QwQ1RVEdJinCzW7GhNy5D6WtgqT6m6pq6QJW6g8KEEvZYwYcIEmjRpEm3atIk2bdpETZo0oX//93+ndev8oH3BggX0rW99izp06EDr1q2jkpISGj16NJ05ExjjOI5DrVu3pr1795rj+PF0sxWz9BB6nkdPvxcm6H8fKavmPD1wceg8aeUC5AcEP66XlYPL2p7M929KAiP0ncG0Sxp4D8/3UeKzHDfe3ZwDATt+mzQw4pBKiW2A3CHoj3M65UAQfkenIvpJXm4Y53TKX37o0f99v2BMjmSkGHr00YP7I+FIMQSOkEnHVeVsoOqL79lorMz9HRVD3Iu4md8cvOJ4VwozLgR/j/dZkEpKDGdbrG1pTyX6+eFZ0FwYJGF9YG3HGfXxdXL2XDAeEZVOCYHC+L9r3plikjmSoD+3+gtDYKEIkYx/hHkhl0tLgn5UfZEAklbl8JtQ0X5pmKw9Ab8J+5JEEQKDssubFZgkiSSoRnLzzs5FdGM+MSAZN4gRX1iXD/SIJpV2MA3zQoy6kxqiYWQdFBNS2Sx+E76nRFXAFSHYiyRTSOyRdY4rmy6A9YxkmnS6AJJ3WJfSKSS4llemnC7A1T+OK0toEgUTXXBESePtdbLvaFWCHjWezYZtUHZDinfzEKYKyXoVtjbATeKkcR9RVUWINAmHuAGH1NcCCVccUl+LukKWuIHChxL0OsR//ud/Uv/+/YmI6Oabb6ZmzZpV+/eO41D37t2/0mdm6SH0PI+eyhN0vJSlwSKCRAT6ca7ONkB+UBWVEFAua4O0XhIYoe8MwZjjyirhwxbtCH2W4+bokICAoo8Sv01KQDnQ143RNRICxQNHBP8SN34E4T/pXGQq9vNi3Pj5yw89+k8NWGyCx32Cqi969EG4r2wh6x9E4IjKo5SMouqLF7XUSA3mcHCBl4xnW5FPdtzeaYaRLkvGs6Gf/4m+C0zyKs4HgAPOtiBt0tFN6OeHA790dBNUAVjbbwiCpPKzAUHHqDwJgQKh+VHrqaZfW6IImbBqj3l20rQZdJ/mmxBx+b9EEYKqL9al1IwLxBwVbWl7AtqDUBmSKELQL/qD5pON5FPSW4zk5k+7zDSVzjh1DQdGfGHPbRhzTexg2h3jmxfis6SGaHi2ocySymbh1YHvKTFE427euOeSKRuYlnEFG1kncb/GeoYa5KZ2MlKJhBO+41XCfRbXEtdEmryDmgC/TzoJBp+D5HJUG4u9TjCC8ZImk1KZF8KgDN9R+u4hCruIS01b/5WBBGqa542oqiJE+j5G3IB79/yQ6L3BXitISCK2lSbv6gpZ4gYKH0rQ6wDnzp2jESNG0Ne+9jVav3497d+/nxo0aEA9evSgW2+9lf77v/+b7rzzTpo7NyxZdByH/ud//oe+853v0DXXXENt27al8vLqiduZM2fo6NGj5igtLaUGDRrQwYMHyfO8Oj1OnjxJT3b3CfpN+ZflUwMWic79fb6nFC/Z1hPWis7DJvvKJ36w2Oyz1Ynn7DnkvxAuaJSj5wf7m+6guVsSz5u7aZ8hoHgp7C87kXjeoHlb84HwEhM87D50PPG8JmNXh37blS0KU98TfNen8sTkH6NWJp5z+gxTGPT370vfmSWJ580v8U1bftq5iB7IB1lT1+2JXSvjxo2jkydP0vBFfpXs6QGL6Pv5qu/W/WWJn9dqvJ/AeDVfqbykySTRNflTXq2B3/ZY73mi8+7Mk8qX8qTypaHLROehko0q2YezNiees3iLHwDe0WkG/eJ9n6BPi7mW/Bi7zFdr/KbvfEO21+w6lHhel8l+0HJbh+n5ZMIc0W97MZ8c+XH+vNeGLxedh8/B2n5pWPS15Ovk+Mmg2uWOWSXeJ9aVHjJJBNz7YQu2ia/l7z5cYO79ws37xdey0ZiAoEv2ibdHrwqtyzs6zRBdS6yrZwYuMs+R5LwftioM3YO3R69KPGfzPr/14ooWk+nlvIpBsp6xdzbsUkR35H0tFm35MvG8D2dtNnuK4/qGaEnrxPM8ejOfwPlZ17zq5aOFomvy9IBFhrxK3yee59GPWk8Jfc9B87YmnnPydJAoxj2XXMs1u4L1DIn8HsH7ZMxSfz3fnP9tV7eUvU+6FhaHvuPlzQpSXUtck7+PXCE6DwlJxAIfzNgkOg/7HRKiBat3J66THV/6ZpyXNS0wxKtk75HEz5q2bk/oO17UeBKVl5cnnofYA0f3qRtFv2359gN0Q5updHvHGVR68JjoHM/zaPyKXXRNXkXScdJ68XlnzpTTbz9cQFe0mEwjFm0Xn1eTY/3usLfP5r3J7378Nn6e9H38Tj5uwL37Y7/ovcFeK4ihENu2GLfm//S6fNXj4MGDStAzBiXotYg1a9bQf/zHf9D/+3//j7797W/TpEm+wcjChQupQYMG9J3vfIcGDhxIK1asoNdff52+9rWvUUlJIIvp1q0bzZo1i1avXk39+vWj7373u/Tcc89V+5ktW7as0rfeoEEDGj58OI0bN67Ojz/mCfoNLSf6AVK7CaLz7mnvn3dj/rzfd5Odd0lj/++feNc//3eC8waPGudn2t2J9Ghn/7zX+4xPPK/z4PF+kNhqIl3YyP/cj0cmf8c3+/rnPdxpAl2cP2+g4LzfdZsQ+m2XNJ6Y+n5c18L/vIc6+f/Gr7skX5+xn40zL70H8+e93Cv5+rw72D/vplYT6adt/c99Z0Dyee6H/vV5oOME+kET/7wPRyT/tqfya+23XYO2is8/Tz7v/g7+3/+yo//fO9vIriuu5ePvBudLzruoUfAsOG6OXhFcy25Dxpnn6M42/vltBiaf16yffy3vaT+Brm3un/f+sOTviPGIN7eaaP4r+W1YVzflz3u4k+yaXNM8/Nw+KDhv5NhgXaKV5o/dk8/r9Yl/3tXNJtLD+e/7Zt/ka9k0fy3vbT/BXJfOg5PPw7V8svsEutD1zxs8KvmaYB1jXV7TXHYPftImuPb4vpLzvp9/1n6T/9zH300+76MR/rX8fpOJ5jmQ7A1d8nvnza0mmrXSRXAtX+vtn3dba/+cK5rKrgm+G56dhm1l5/08vzdcn38P/bar7Fpe0XRi6Hu+1jv5t41h+yzu+auCa/kBW8+X5t9/Az5N/o5Yz7j+FzeSXZPne4bX5YVuumt5e/6aPNJZdi1vecf/++vz++0LPZOvybhx4+jKpsEacdwcteyffN6AT8eZd+tVzfzzen2S/FntBo0PrRPHzdHYz5LPe2fA+BCpfK6H7Jq83Cs4r7ngd+Hgn+W4OfF5g0YG5z4gfM/V9Og9PPw93xLszePGjaMW/cPXUvo+hsoT9+4u4d5wX/vweb8T7g11dQwfPlwJesagBL0WUV5eTps3b6alS5dSo0aN6Lvf/S6tX7+e5s+fTw0aNKDGjRuH/v7qq6+mRo0axf57Y8aMMdXwOGS9gv6HPKm8L2+o9WgvWXXyN339/jZUC6WVOLiNo9r85sjkCvHOA75E8JImk+j1EX71tVdRcpZ+ZrHf83Rvt1kmS795X3K2d8Ac3wX3r0OX0hUt8ucJssRvj14Z+m0XN5ZViPnBK5v4Dknn8Erl3/LnvVu4IfG8ORsx4mumuZ+fLdsZu1bGjfOz00MX+DLW5wYtphvyVZDVO5Orvs0+9yXB+K/j5uj4qTOJ5yET/pIxi5stupao+jYe61c6n+ovq1RCOvlUvqIkqZpwNcJjvf0K6fgVuxLPG7XEb6f4Q7+FRj2xQFD17TjJNySE58BtHWXV2z/nZawP9pxjfqPkPFQosbb/NHBx4jo5fDyYl4vv+/bo5Od91c6gNQVqC4kiZORi/1r+sd/CVCqGDvnv1nLcmlSKEFR9sS5vaDNVdC1x7fHbnug7X3Qe9iI8P3EqBn4U7/G9Ea5pNcWoGLoWFieeNyu/d97TdZZ5NxRt2Jt4Xu+iEvMecVy/cp+0TjzPM/vd4/mZ2g8KFSF/zPtL3Jv/jq+PkL2HoEbA9+wxLfkZP8b2Wdzz9wXnrdzhr+eb2k0zn1u8J7nqi/V8/3uzzedKqr6d8j27LzFXdsl5uJa4B88MlO0NUD3gvx0LZJVfVIrRjjJqyY7EdbJ1v68I+UHzyea8ZdsOJH7W5DW7Q+vEcXN05PipxPMmrCwNkcrmn8uqsO9NDZzH+81OVlngsAm69LyNe4KRsn+IqTD/sw4oQnB0m5K8n3heoAjBIX0fN8/vd7h3D/WcG/l39lqByvOevJeMVBFSV4dW0LMHJeh1iLvvvpuef/552rZtGzVo0ICGDh0a+r8/8cQT9Pvf/z72/N27d1ODBg1o0SLZfFKibPWZeJ5Hv88TdMwOljoRo9cZ/31xqGz0FebIYoZwnOEHB3cifnu0TxA+KEqeDz4733f28/fmmB5FiRMx+ihfGb7CnLd5f/J5+G74bY4rM6XjQNAB0yRJL+bJ8rPm8xrlCVRHgfv73BLf2fa+7rONcVtcL6bnBf1d6NF/fshS0zO6UtCfClOtDgWBK6ukFxN+B+hjlppx4bth/J20dx0yVPTsdp2a7GYMv4O73p1JGCkmmTQwKj/S76kBixN9ADhwDdHHLB0hCF8FGOc90Vc2u9u0suSv5VOC8VlHTwcBJ0ztJH2HfGTdP/Iycsnzjmv59MDFhngVCtzfcS3bTFxvTMo270/2AXgzP1Me61JqxgVvA+wXUv+A7zfzCTpMk+J6MTl4Pz9MLCWTIfjeie9bVJzsdN43P+ILz8ClTaIdy/k6ISJ6LW9eiH1I+ozDowCmmi9/IvNQgd8DnoNugmec77O455LzVpceMUQUTvzr9yS//zHu8zE2LaP8bLJ5Yee8xB3fUXoeriV6d3/7oWy/vDtPgOAaLzWXwz2A70qUsam9TjBT/soWhfTTvMdInLEpB8ZZcsd5ibEpjPpwSD074APguLJJNYBN0KXAnplmT68p+Gc5rnw6ymcrwskO6fsY3j64d3HTDOy1gmcb+5ck1qxLZIkbKHwoQa9D3HXXXfT0009TZWUlfe9736tiEnfttddWqapzTJw4kRo0aEA7d8qdPbP0EHqeR7/LyyVhSnZvN1lgBKMjvMzjAnYbqE5idIYkoOJOxDBmkoyAmbnRr2r+4v05hmCs3Z3sRNx/rk/Q/zZihTETipsPzvFWPmDnY0EkgREHKpUY2Sa5rsfPBIEjZjPHzQrlQBB+/3tzjBFbnGM5f/lhlNKLQ5cZI7bF25KDJNy7blM3me978PiZxPNAQpF8kJpxwSUYc1QlRIgb7sHxXEJoMGf3Z11nmYTCGIHx1Mglu8xzlIYItbcM96QjBOHCDqOxh3rKEnJ4DrC2f98vOrji66TsZEDQP5rt+zq8JHje+ci6pp8HayYJ/FpiP5uwKtn9Hdey3aQNqQgUCBDWpdSMC6ZazVngKQGcyvH8PCMYrQeDsuvbTDW/U2LMyffONKPues/cEnovOG50ktIOpl/NmxdiPceZy9ngiSasawlgVornQZLQ5PssEqgS4yk+zjJNQhPjPrH/OW6OjqcYZ4l16bg5OlmefB4+5+W8skO6LkGwkRSTvHuIgntw/3v+8xBlLmevE8yUv6plYaqE5uS1e807II2x6fi8UR+OV4fLpgvAeNJx48eCRcEm6NIEP0wdHTdHj/SS3beaAvszjleE1wTmsjikiUkk9vGM3911VuTf2WsFJomYZiBN3tUVssQNFD6UoNcSGjduTHPmzKHt27fTmjVrqEmTJvRv//ZvNHWqX3nq3r07fetb36LRo0fT5s2bqVmzZvT1r3+dtmzxx0gsWLCAunXrRitXrqRt27bRyJEj6Xvf+x499NBDqb5Hlh5Cz/NMHyXGpklHuSCrD1fox4VZW1Qn8QJ7YUhy5Z07EaMKJAmMior3mwzqbR39wGj5zuTZ1P3mbDUZ1zRu0HCB5i9nSWDEASKEKoikilF2KiBCnfLBmWSePYLwB3rMMSOmBsbMs+cvP4xSemnY8lSO5Qhqe0wvMUqKL8pOJZ6Hahzu/R2dZDNskezAnOsHBWSUjwZD9VbiVDs/P2f33m6zjRuyZNTdiPxIv+c+XmICiclrk4lQ25yfwAFJlI4QfCb/nL/xKUy5ooMdG3B9x9qWzLc+zMYjIqkjUYTwkXVIVEkIFL+WaZIkuJbtCzakIlCYKY91eZlwvvXP84QEyg7pfOtLm/gEvU++Sh2XJOHY8IVvqnVD22n07pSNJjGQBL53Yu56bnXyKDKM+MJYPceNnpxhB9MghUiK3dZxRuJnEZFJxKDy/rQgaUFExqz0pWHLxaSSK0Jwz9sLRt0tZxMe0iQ0h7P1jM+VTBOBwgLf0XFzVHYyWamEfRaO+tJkPSrZIETS+dZoO8O+F+WQbq8TzJT/YaspqRKafJwllCiScZbjVu4OkUrpdIGuLAktiXEAKHhwnDmbPHWGKHCpd1w/qfZ/CezPOCT7EFGgCMEheR8TETXOJ/bxjMe9/+21AkKPdZnmPtQFssQNFD6UoNcSnn32WXIch772ta/Rf/3Xf9Hdd99tyDnQoUMH+t///V/6xje+QbfeemvIxX358uV0880307e//W36+te/Tpdffjm1bNmSTp5M3uQ5svQQep5nTJ8g5/1xB1lghGw5XuYSaTyvTvaaudkEH0mArO2K5pODYFoQGM0o9nusH+o512T5JbOpP5y9xZAYjJdatiOZ2IP04Lc5rmxGKweIECTBjwqy4ZwIQVoXN6eaA9fnwZ5zzXfvOyt6ril/+aEF4OVPlpsZuNM37Ev8PN6egAB5+4ETiechCMe4lVvbT088hyhIdiDhIpHN8tFgyNxLJHy8XSDNOCu0C/x58FITSEik8SCuqMLGESEbIK74bdLn/dp8qwfWdlyVhq+Tg2w84kgm5U8CH1kH+fk7E5IJ1CeLdpprmWYcI2T7HScXpyJQIJOoTF/UeFLiOURkKn9Iwt3TTZYkQeVvUP75+3Wf5ArUuj1+teumdtPMniKR6U5bn987P5hnqtSSdYlkGPYTx83R0Yg2FjuYBlHGHnGjcE41kgd45qSybJA0JLgkCU2uCMFeJFmXfJxlmoTm0IVBK9HFKUaKtWOKEHzfAwKlEvZZ7C23d5LtDXfmvTOQ5G80VlYxxrQMVO6j2ljsdbJ5v68IufadKakSmnycZZo2FluW/Yd+snZGJMOkzynAJ844bo6OnExOyBARTV4bSPGlSdeaAvszDmk7ChQhuO/S86AEgbrm5nbR7397rUDliXX57KDkWLMukSVuoPChBL2eIUsPoed5xj0X1aDr28gCI/QDoQoUJzviqGBzZEGanhQE7EbW1qLQyPckgRGCzIc/mGcCo9mbvkw8DxWqv49cZYj9IgGxRx8lfps0MOJAzzv+jQd6JGfDORFCcuG1EcmyM359kGjpMb0k8m/5yw8tAK8OX2GUFAVrkqtraAHoPXOLIXybBJ4ACMIhVb9BGLwj2TEkH+g2FKhDTnvnzLXE2m76eXLAydsFXk5QI3Dgu70wZJmpEIxauivxPFTHeD+/pKcSfaY477rWst51BLVYl3EJOb5OvjwWrEtUoiQEatkOPwC8s3ORqURJ7gEnNCB8gwT3AG0hnQuLzT4xpyR5n8B95sG4RMXws3zPLpJpknVJFKiPoBSQVKDQL3pL++mhxGMS0LP7SK95if4UHPhNXF4dtQfawfSLeUMzrOsftpL18/86b2iG99evhLJZtAtA1fP26OSkxSGWCMU9lxD7xdsOmfucJqEJ1clfhy0z1eYdB5MTmti3OhQUpyL22Ge75n+bNBa4PT+GD20zb41KTg4TBYoQKASivD7sdbIp76lwXeupqRKakKr/9sOFpo1l3Z7kdjdbli1JmBMFPgCOK2/XICLjBYRDojAjCicS7uwsU5jVFNifcUjfx0igIsaR7ntI2iG+ivP6sNcKEjgg9pJYsy6RJW6g8KEEvZ4hSw+h53n06y4TQgHVVS1lfZQINNAPKanEcfkwgg+JUQhkbVe3LDTBgyQwQpD5aK95xu166vrkwAhVwrdGrTLVLknFA32UA+ZuSxUYcVyVN84B2ZBU1/Yf892FL2iUM/Lzvw5LlnMVsuuDSmycoQ1/+YGkvTZiRSpDNFSr+s7aYuTnEk8ABOGoAErNuJAEQJAlWaMnWJ8pgixJ8M7bBUAWPppdVbJpYzALwpN8ADhwv7pO2WgC3T1HkoM5VENR6fx+s3DvemVlJfWfu43mW32dWJd4buOqH3yd7D/qr8sLG+VMhUdCoJbm+yl/2mWmkUxLFCGc0OAefDg7WhHCAVL47pSNqQgUkgA9mCGUxHPirnzSD4lASaWSq4+Q7JBUoGBQ9uMOM0zlXeIDwO8XCJREjYAWiKafrzFtLFHr0g6mEURDnm2vyzggCMf7S2pyimcGyRlJQvMAS4T2YImIJCxkBpJpEpr8fqUxOUUFvNPkYlOtlMi5sc/C6E/qa4G2ECSspGZceEfivA4FVdtY7HVSvPeoSR6kSWjimflDv0Xm+64QtLtB+YO1/HNhOwr3oblG+L4iIlPtxbHly+QqP1GgxHLc+ApzFIqK91Pjz9ZQu0kbaP8xWayC/Rlr6+LGk0SJScQ08IaRqreQ2EcRIW5d2msF3hlow5Sa0tUVssQNFD6UoNczZOkh9DyPfpUn6Gn7KOHYiqqMhDRx+TAMneJ6WTkga7vmnSmpAiNuDAO5U5o+yrdHrza/s2hjcp8bAo1B87al6nPjuDJvnANS+RNBNnxv2WnzouR9i0lAEP5Y7/mm6hLXOsBffqYSN3KlCShGCoIkTlxRdZG0DiAIx+deKTTjQtUX8kZJpv8Y6zN9P4XzOHp2H+w5N5Xz+EAWhCf5AHBw87Q0kk3IWPG5jhuu+uJ3OG7YQRjrEs9tnFEfXyd8XaKdQkKgTMXx3ZnGdo1p5wAAIABJREFUXE5CoIw3wifLTdWl54xoRQiHSXZM3ZSKQKHqi3XpuDk6ITDxQs8u7oEkoD7H1EfY1yQVKBiU3dZxRqgFIAm8Zxe/c0iEiZcNKB6aj1tr1kxUG4sdTCM5hYSvtF0AQTjeX9K+6Ysts1JJQhOJ0Asb5YwZ3puCavH8LX77y8+6zkqV0BwwN5gmksbkFNeiS+FGk1jbKiB62Geh6rlQ6GsBwgUPFkkCiIjowrwiBNMQolRx9jpZv8cn6De2nZYqoYkK8x/7LzJtLBJVHGTZ2GOlHj1INOE4e05mFsv9BqT3m4hCqr0fCVVRREEbGJ49CbA/I9HhuNFtLDaQQMX+J1VoYF1hXV/SJHpvsNcKVJ5YX2laDeoCWeIGCh9K0OsZsvQQep5Hj3b2CTokr1KzKTivInN7ebNkYs/lw8hoPyxwit3ERgWlCYwKWJCJPrfPViTLNHkSAJIzSeUdxkiDF2xPFRhxgNhjvIuk39qMoWtSQGOWBYFIEkwQ3neBMZeL67fmLz9U/t4ctcrIGocK+q3Rs9t/7jZTRVywJTlIQhCOipI0iYR7ACm/RDbL+0xRSZI4907fEPTswtTmvWnJ5JC3CyT5AHDgM96fXkI3t5suDuYgY+WGPafKg951PF82Qce6xHMbJ6Pk62Q3W5fo0ZcQKFQc7+46K5UihBMa9Nh3FYw44pMh0hAoVH0HsWSHxIwLPbsgzJIReR5TH0GtIalAQY56R6cik/ST+ADwnt1XmDIoCZB+txy/jn6UbzGJamOxg2m4qfP1d64i+T2EIBzvLymBAjl8b5q/10sSmvuOBgknEKK/CRJH85iBZJqEJlcqIaEpMTnl6prq7oEN7LNcLi3xtYAaCu0CkvF/XBGCZGNUG4u9TvgIxjQJzTFs7adpY8EzClm8tC8fXjk4vjwma3Xj0w8cVzZCjohCKh5pApsoMOqr7t1vgytC0vw+7JO4/lcL1Zp4L/J2roqIvcFeK1BD4V0piTXrElniBgofStDrGbL0EHqeR4/kCTp3HvcE2V5ssp+v2F3tpsnB58iCPEt6rANZ29RQ0JIEkNwn+i4wL75PlyTLNBG0Nf5sjZH9SSpqMCoaunBHqsCI49J8byQInyR4h8v95c0KaMKqILBOAv72Nx8uMPc/biQMf/mhBeAfo1cZ1YAkeOe92XCyniXwBEAQjmBJWl1DBQ/kUJJE4n2mqHBKyOHUfBLgkV7zzNxWyfxbXiFO8gHgwN/2nFGSytgMFWIQMMcNj7rj7sMc6NnFcxtHDvk64esSVRcJgULF8Z5us1IpQjhpgvGbZCYzny6QhkDxCh6umcRzAhMlQJgliSOe3FyUD5AlihDeLjCePe9J4J4Bb6RoF0BbSKsJ66pNHNnBNKYLcGUHTxzFAUE49i+pbBafgSScJKH5RVmQcOKTLJIwp+RLQ0zSJDS5Z8BdKUxOubrmxhT91thn0frkuDJfC5BXVDglZlzcjwZkNqqNxV4nfARjmoTmqHxC8pmBi027m6SNBbJsVIulBqXYf3Bs3CuLAyDbxyHxzCEik2DH+pQCMvW46x8FTCy5p9ss0yqyW9BehQQqEkGS9zFR4O3DY1TJZAioH7EuJbFmXSJL3EDhQwl6PUOWHkLP8+jhPEFHVdRxZTJN9GaDmDhu8kgxPkcWBFTSRwlZ2w1tp6UKjCYwYxjjrC2QaXZjxlRpKmoIvj5ZtNNUFSSBEQd63fASlHgC7DwYjKErZOZOSUAQ/ruPFhrSHadM4C8/9C+7Y1abvvI+giAJPbsfz99ugkGJMgHjdMYww56kZBBRUB0ASbmwUS7xHN5nioTAcx8nV4Rw3X/F2wUE5BAE4Y1PVyb6AHBwGf39KZIdmL4wee1eQ7pLDwdtGNz5mVcwEYhBqh5HDvk64euSz4JOAiqO93WfnUoRgmTH65+uNNLlVhOSq0JIdnxQtDkVgeLj9NKMDUSwj/3pB4Je31PlAUHHmCMJseftApDGS4yukHj9Q79FoekLScB1bz1xfbUTMOxgGsQECRnHlakREITj/SWRzfLqLd4nkoQmFCGXNS0wSRnJ3PVZEQaSkoQmNytFQlNC2LiCJ83YQCQ7ior3p/K1uL6Nn4zG3iEx4+J+NFBdRCXd7XXCRzCmSWiiNefZQUtSJd0HW7JsqSEavA1w2J4ecYCJJw6JQz0RhUbqOa58fjoKAo4rn2fOJ5YgCb5NMI0FCVSY+0nex0SBtw+PUSWTIfBexJQNqWt8XSFL3EDhQwl6PUOWHkLP8+ihTj5B5zJNSdYcTsQIph03uXrE58hik5c4nELWdlO7aakCIxDQ3/dbaDb5qFmrNngfZZp5yhjtNGLxzlSBEQekl5idK5Fzc5f7orz8VTILFUH4H/svMi/PODk3f/kFTs1rjDnT+4IgyfSyLtyRyhPgF+/PCREax5XNh0V1AOvHcZN7AWFsdkGjnKm6SGYro5//133mGymeZLYyb9lI8gHgQF9dn1lbTFV88trka8lbNq6NMJ5C9c1xw4k69OziuZU46W7Pr8srWxSaJJuEQKHi+PP35qRShJhkx8iVJsnWJEYRwoFkR6+Zm1MRKKhyRi7ZlcpzAj27MLGUVLy4eSFafiRGarxdAP4CkkrS2OVBYoS3ACQBvbdtc+vp7vw7IqqNxQ6mQUx4Ek5iWoUgHO8viWyW9/Ojx1iS0IQi5PvNJhvC94xgbyhiBpJpEppcqYSE5jRBQhN7co/pJWZs11KBVBrJjpkb96fytYBaDERbMqnhzNkg4QTPlyilkr1O+AjGNAnNQImzNNXYQKwrFCSk/d02YZ6wao/oPLTi4fh8RfJ3JAqSjGnej0RBQcC/NrIxZJhY8vP35ph7L1EIQBHyDDPCk/Tm81aG6mJNe61A5Qlj4TRu+nWBLHEDhQ8l6PUMWXoIPc+jB/MEfdiiHYYc7juaHBhxyZ3UKZb396Kyc0enZBM0yNpuaT/dBEZ/EsjoOAEFoek1M7kKxPson00hjX+WBexpAiMOXB8QGoknwOb9vsv9D1tNMZV3ySxUBMNPDlhsDFxeGBIt5+YvP0jNmny2xsi5uxQmB0l/YZLgNJ4AqB5x6aVE5YHqAEwGHTdZ5cGNzXgVMQm8nx/rp8W45EkD3KU8yQeAg8uOQW4k15K7lN+aJ4qrS4Mk0utsfjXvK8TegOf2qpg+R75OtuanL1zVstCsUQmBQsXxF+/PSaUI4ckOXFfJyCee7EhDoCCHH72sNJXnBGTH+J0XCCpJPLkJZYKk1YO3C8xj0tQk8OQUNx1LAqqo7SdtqFbZYQfT2A8+X7HbPLdc2REHBOEYPSeRzfJ+fiRxJQlNXPcrmk8OmY4lAaqTh3rOTZXQ5EolJDQnCaq+XPFQXZLExv2sSp/G1wIO8/i+EjMu3rIBH44ogmivE+6pkCahyRP7z6RoY4EsGyouad80kgc4Pp6/XXQeFHs4PlmUHHcQBVVmHMcEpm1ERBc1Dgi61OWcTyzBOllTmrxOUAGHV4/kfUwU9vapTtlhrxUkVbAuJbFmXSJL3EDhQwl6PUOWHkLP8+iXHX2CPnzxzlQjWXjfq7Tf+jDr74XkVdLTxWVtvLKTBP63jVNUgXgfJYyghggkr3jxj1q6K1VgBPC+PFTFHTfZE6AkX1G79p0pRs4tmYXKg3BUkuISH/zlB4VBs8/Xmv7BdoIgCQqD4Yt3pvIEQBCOSpTjyuSvqPqi8uW4OTpysnp1CDc2Q5/244LqLTfV4h4GSeCGhEk+ABzoy+s3Z2so8ZEEPpUgqq+V90DyfcB+buOUHXyd8MQR70dPAq84plGE8GRHGhMvkPIPZ29JRaCgrhm7vDSV5wSckxdsOWiua5IhGk9uQuUhOY+3CyzJ7w2SyRA8EZqGCPH2juoMNu1gmrcSXdVCnuy4p9ssQ+wdVyab5dVbyP4lCc3tTKk0IUU/P0wqH/5gXqqEJlcq8QRGEjCWqvfMLWbvlEjjuXlaGl+Lq/PJKVRIJWZc3I8G5DnqnV6VoAdrOE1CE870LwxZZt7pkjYW7CNoDZKOnuNKJMeNnvEeBUzZAHGWKP6IgncrjoMCLwwiogsaBedIkqBE4YklMLxctiN5nUAR8gZLAie9j4kCb58hC3ekmgwBlSfWpdQ/oK6QJW6g8KEEvZ4hSw+h53n0izxB/3TJTvOilcja7mQVYqmc+yDr742TvB44foaW7TgcIgd8VFCawIi7FqMK1GlyeNaqd66iSjaW91G+HOEUW1lZGZnEeIrJ4VH1tZ1ij5wsjx1Jwis7qOQ6brhafOD4mSpZZ26ih7nHt1gvo4qKqt+Z9+WhImRXi71zFfRF2anQy49XiJHMsIOkk+Vnq8jQuMIgyhPAO1dBK3cdqZL9RxDO2yls19i9ZaeryPq4IgSByP4EdQgnknxOPAfuP1c2cL8DBCJ29Xbrl8dp2Y7DVHYq+H2czEf5AFRWVtL6PUerfO9XmbM2J+vA2XMVtGrXkdBnEVGoqhk1QhCVIscNZIu8Z3fDF0dNAMlx5GQ5lZ3yQuuEJ472sZnoSdeSB4BxipBzFZVVKqyolDQau9r0jr44NKwIOXP2XBWFEFQD/eZsjSVQx057VVp/OGmC54Sk4nhdnsyjjcVxw6ZHRyM+iyc3eTXdNlKzryVvF1gVkxSN2htGMHM+7Id8DFZlZSWV7DtW5R7AHKvj5GIzMSCqjcUOpkFMJq7eY65P8d7wO/LQiXI6bilnkAgF0XbcqrLZPUdO0aZ9x8x14dVbVAMlCc0tXwYqED4nPgl8H0mT0OQz5Xk7RRIwlqrvrC1GMTOjOJwkKTvpVXkPgaDP23wgUv1wqvxcpFs3Eiro549Kpu0+ciqUTOLjLKHkimpjsdcJkkwNu8yMTWieq6isYlqG/eCvw5almkoAcof1ealwgggKAjiiHOqjgGcGsZhkTCRRVWm8xAuD7+uOK+/R5hNLQILnb0nuscf+/Pbo1ebdnPQ+Jgor79JMhmiYT0BjXUrHutUVssQNFD6UoNczZOkh9DyP7u/gE/RRS3cZN9b1e5K/Gx/7Iq0Wf3nMJ+gXNMqFZpsDx057JkPquIFsCoHsHZ2KQrO7kzCSObfCKKSN1RcMoyduZMT7KPnsbgA9xnb1l0uNowIjBIaXNS2IlK3zys6Rk0FAfigfrMNh3HZ2X7fHbwG4se002rg3GEnHgWoMl0jyvjxItG15In7T0m0HzMuPk/L3Y+bS/+L9OXRF88khgvg0Uxj8LYJUIhliB8t8fUWZce04eIIubFRVIsnJvFQdsuOgXyW7ovlkI019sGd4djdI9SCWtOF+B9ysDODV/5vbTTckoiszJOzPxoQB+LcuaTIp1JOLvrxB87ZFVn3xv93YdlqIsPAqWZQPAJ9ti4Qb79kFSXHcoPUC6/aSJpPo9Jlys06wFq9rPTW0nrkiBL+ZB6I8AETFzJYnQsbLq7NYi40/W2MUIbajNHp5t7DqLB//B4k2J1CVlZXGcJATYl71TeM5AUkwnlvHDSSplZWVZq1y0s7NC8vPBok8riRBwo2bE/J2ASTyrrP2BpBq3iLBJcHo4WzOWjaw3h033H8Kc6zOhcVm7xi7vGrrhR1Mg5hMWvOF6dHnrRcgdHZrBYLwmez54gnM7UyJNDrvI8IN9+CIbyc0o4B31rXvTAnWqLU3RIG/s+ISmlHg151XEZPwBntnofJbuC4wG+Prh5NmJELnbzkQ6WuBpPzesjCpuiL/bOB9Yo9SRM8y9zcpOxUQdLx7oiq49jpZxEZ8xRmb4nnm/froJX/5k+UmgSFpY+nDXP4dVz5BBPsv1DKSSSBEZAzs8AzYBYU4YIY9jh0Hk03b+L4e9d6NA59YAn+YmSzJGweuCEmj1uTePmkmQ8DYD8nGa2J8U7KCLHEDhQ8l6PUMWXoIPc+jn+cJ+phlpamCTP63qLrZWXobqKJd1HhSyEAK4GZePGDksjbIBR8SyOh4kP5uRJBJFJA4Top4H+VbEb3rOMc2aeLmM1GBESqKdmAN8MDxxJmzhhTAIRWEkZMjft1ubjfdzES/uPGk0N9gJFTnwuCFjyD8+SFLTaXN7k/F570+Yrl5+XGFQdQosnMVlaZizYNsLgmGBJAb/CDpYwfZCMIXbzsUacaFAJgH2bw6cOhEuUk+JVU4Td90i8KQGU7UNXHcoBrM/Q4GsmAQQCUGB6R9XI2AhBJ3QUawicAZQF/ekAXbTUKJVzghL3bcsNmWCcI3HzCBD5fG87E7+Dwe0PN2gfKzPtHm/9vew8fNOuEqGa4O4cqKqGvJA0AYotmO5TjnfnZv+PQFnjCJOo+3unCVTBQZ5RVrXtVFVW3Cqj2pPCcCpVKwH6BizqXs3Lxv/7HAvLCystJIYLkaAM8Gv5ZQI/yyx1zTvnFJk/DegHN44o9LgnlgDXC3fy67hlLp3SkbjWJmxOKqbSx2MM0J4Z0R1xLEzHHDExwQhC9k/3cum8VYQOznRGHDPagK7KRFFLAWr2s9NeTMngTjT9EnaH/h1zIOXQoDLxQoZvoLqr48+RmlYsC4OMfNhRKoSIQu3HowMrmCc+zENPYMVMJtMy58B74uecIO77Woyru9TtAW8rOus2KNTfHv8iQ+eslfHb7CjFWUtLGgbQaJfMeVOaTDeBLrU2I0ShQQbbQY2AWFOGB0XNTeEQe+Jzuu3KGeTyzByLQp65Ld5rkiBHvgFkEbC1fepZkMgX0ErY5p5sPXBbLEDRQ+lKDXM2TpIfQ8j+5r7xP0z1aUpuo74wZT1UkZORAYXNJkEpUe9oN6LhlD0IMDxIHL2tIERrxCjF5fd0y40ovP4gQdfZQdCopDI2vsc+zxSBgfMn7VHnoi4ppwSWtUfyUfQ3faO2fmJaO/C4ZPjhsm+LxHn8s3+d/gxc8r3QjCXxy6zFTz7Oo8/q3nBy8xLz+uMAAR4vJEXu3j8mkEfZ+v2G0qx1yeiJev44YJOIKcpdsPRb7YkWi4lCkTeHXgyMlyUzlOGkUG0vTDVlNMMHh31+ikBQ84EQQ8OWCxmZ37/JBg0gCf4eq4gckNr6ihKsddtvnYnYmrAydgVNSGLtxhyD8fU4QWC8cNk0quRkAVGmOKeF+o4wZzgvmaAlF03KD1AiaOjpuj9aWHzTpB4ujGfOAHZ2guT4y6ljwA5GuJV97xv/F9gJPrKRHmcjxpw59nPv6PG80BvArLey35vpdG6nkV66O0Wy+2MoXC8p1BEMqTm/zf4OONkNDj15JXekN7AyNm+N/4s88lwVHXBFVIxw2TRphjdZ26yUxtGBwx2tIOpnlC01xLNpqKK1B4y0/QA3s4UjaLZ9Fxfc8MorC8GiqPONNDjqCVaFoqM07uT4Fr+feRyeaFnVhrwZusrzwJXMKNpDFPovCEGr9WPBEa5WuBc3i7F1Fgxok2H1vt8kQEQeftbtVdS3ud4G/v7TY71tgU/y7vaQeZf23EilSmh5Blc2MzifM47hfeO1IDNiRWcZ5EaUEUeIvgkLTacMWe9BkgCpJev+4z39xb/m6KA9+foSzY8EVyHCz19rHXChL+eP4kE3HqElniBgofStDrGbL0EHqeR/fkCfq4lbvNS2FuSXKQyaVGXLpcHfgc2f0RPanog8YB+TOXtc1P4USMOdZ/Gbw0NG8a4KZsnKC/M8En6J0mF5ueVF7pxTl2BZ2T8ihTn2lsZvySiEobr9SVn60wclxkp2ezBAYnqMvZ6BkiMm0CPAkAksvH0/GZ8pwA8AoVPu/J/gvNyw99lO0nbTB94Ty42sSUAnw8HZcED44IrvDSdtywioNnza+LGOuC5Ivj5kyPKq8OlJ3yTKCa5HSO7/6j1lON4Z5tqsXXKAC/A264x+XV7VnF0XEDnwe0S7wzYX2kceL9jGhzJ2AoIj5ZtNN8Ng9IUdF1XL+nFEASbtHWg0YJgSCQB+486OLKDi5NRQKIy4vnbtpn1gmfvkAUEAAeXEVdSz6yjqsxuBIA53CCziuOUITwvkpeneYVdD7+D1LYl4YF6gc4RztuWBHD5ymnmVMNIr3z4ElDbtAzizXnuGGJ7h5mXkhEke1IURV0rkbgn82JPc7hBJ2rQDi5AfioJK7KgTKm+7RNkW0sgB1Mc0O5KG8EBNmOG/afQBC+YufhSNns+2xvACnmaxgtLZLeYihCbmw7zSSNf9plZuJ545k/xYCINpY4IBHaZuL6yERxHHj7S9S7me/P3GyLJ0JtXwu+n35QFJ6EgrYjJMXsdoGoCjpvd4NCLkpiba8TPoM7bqILPou/69Aq9ManKyPbWOKA9cOVTLz1JA4wnkSFWdKSRxRUwvFfyZhIovB7wnHDyb048ISd4/rvfok6ILc6mFhSXRuLDb4/Q4G5SqDW5N4+aSZD4DOwB0rnrtcVssQNFD6UoNczZOkh9DyPftbOJ+jjV+2JNZSJAkYFrdtTVm2lhIPPkT3ETI9ACBEI4kBlj1cyMeapoSAwGspkmibwZrJjLrPjcmRk2DsXFpv+zA4FQRCKc2yCjp7egjVfRAZGIG6O65sa2eDf5+y5CmMMBIkoHzPGCb4d4IDQcokoxkBxUyME4a8MXxGSMXODKvxvj/WeZ15+/JrANIxLRHml/8PZQcWHG0EZh/Q+QeWd+w/wNQglwYqdhyPNuPjMWfTe8erAsdOeqSolueLi91zfZqohzD/uMCP0N3yNApCn/2nQktD4OsAeu4PvD+LeNrfePB/cowC/13HDTsCQXH66ZGek0zk/bzybwcul2LZEFL8XB8YQcUkwJ+uQqvPZ1eOW7zLrZJV1/UBouaok6lrykXVEwZxlKAF4Yo0TdFQcW01YFxn08/55PqMers7DFu2IDPqnsOduOJNr/8rIsvem2jtBJEsPnzT9u1i33OyMS4mhOEIVKMo9OYqgczUCUUBo+Xk4hxP0/kwSHLV3PsgktVyVBCL5/vQSI/O1CR1R1WD6ITb+L6o9CAk9xw0TcB7oR6lrWrDnDkkXvs/uY474SeSEtxJhHvdtHWdUew5R2J8iSl0TB95qxd9JSeBjqfjkDGAVe855BZOrEfgsdaJw8tiuPKPdAuo224yLE3QYee5nCWE7kcdhr5PZTEEXNQaTK6f4BAf0kv995KoQUUwC2mZQEXfcXBWjwijAuwZJadvHJA5oF8Re+fbo1cknUeAtgoNP5oiDrZji96c6cKNevIei2lhscEUIkkFRhQob3NsnzWQIqDy5MrMiYepFXSJL3EDhQwl6PUOWHkLP8+juPEGfuHpPpDFMHLhECdnivgmmK3yOLH/h46WAih6OjnmDFF41t6vF1WEIk2mimv5nllXnAftTjEzxqjmvYhCFAwCboD/GAvaowAimNo4bPd+Uy/4qKytNUIAAFwEJPgOwkxZ4iSHA5eSbV3wQhCOQucr0xgYBLs574P055uUHI6hOk4tDSggYDvFqFzes4kZQIPF35fsVKysrjUTVccOJDR6Eg6zzCvsrbAYsKge8OnDizNlYF38bXJaN//dN7YKA03a+BZB8ee7jJaZixmWNPMBz3KCNhKsROBE+ceYsVVZWmuqU44adgI2r89Jdkc79uJeOGzaz42oE27mfexwgwCcKS4LPnD1nxtfBqA/VKcfN0cC5W8w6sUmMGVnIEnlR1xLrB5Ma7rYkz9zRnPsDQI3QeuJ607LB+yqXsOo0N/CDGmH44p3m3vEpETAZ4s8iEZnq2NT1+wxZLxT0YqJqvufIKSP7xzOHfcpxw74XPLlJFDb7AzhBx7PI1QhEVEWVwxNZnKDzqnkUqeRmgnxPBbHrOaPEVNO7RYyYsoNpEJOi4v2h3n4ARMlxw+oZmGmtKS0zqgJOOuEv4Li+WSgRhZLDnKzDUyEOIJK3tp8eIutJ4DPTuXFpEnirFU/kJYG3v0Qlz/l4P97Ly9UIUJHhHcwTGTaxhcIF/65txoWEi+MGBnO83Y339tuw1wmfwc17+wH+DuXklk/WiPJUiANk2dyVXTLiExV37NO2cV4cYLoGBR5X/FUHeIvgkCh5eEtdmt+GhNPvPloYSgYlgcdSmFHO1V1x4N4+aSZDQOXJ17skAVFXyBI3UPhQgl7PkKWH0PM8uqvtRHJcnzRxCXISuNS4yWfxgRgHnyPLCRQy0uiJtQMBLmtLExgZCfcny0Mj1wAesP+yR5DhbvZ50EfJTbyIwv3V9kznR5lhStSLCwEXAlgbXPZHFFRXUe0bzogCJ/h2rzRMVZAc4MHV1S2DPjPbbRzVVZBHLmts2GWmefnxHj7+N5i9yqtdfNQYTwCh9/PafDBn98PxZA8PwqMy73iBO24gC+bVgVPl50xQZnsQ2ODVHC53B+ygBlU33Js/D14a6tEDXmJEwXEDiR4C4Q4FxVRZWUmXNQ1kujyJ5bhhIz7I/kYvKw38HJoElXdO7Luy9gwQqxU7D5vKAkjuqDx5wAGXYy4J9s5VVDHqAzF23By9W7jBrBNIw9GTCnMmyMttF2FIR+0EB4IyEDbMV3fcsLqBk5htbK8BeHWaqxu4GiHKhBJGUY4bNuID2Z2+YV+qXkwkOPaWna7Si4meVwSygG2qGWXOhLXjuIG6wVYj2KocPs6RG/GZlqCRKyNVBTwZwFU52MM/KNpcheRx2ME0d4N+kklaAezJWLsAV9REyWbxTnPcIOnC9/Co91AcuCKETyhIwhj27okzL4wCT4R2td5D1eEvrP0lylyOJ+I4QeLXz3ab38Z8GLg8nycskTy3zbjQVuO4vuKOKNzutj3iWQXsdcJHMEY9q9yIlZNbPMNvj15t1rbEB4BX2+33XHVA0hhxgKQVgijwDsFzKmmFIAqSmPZ7sDrY7xfHlY1n44aoUSM+48AVITwhlwTu7cOr6TbstQKVJ/f+OSFQP9QVssQNFD6UoNczZOkh9DyPGuYJ+uS10bLsOFybHxVUsu9YqApYHbayObJnGbGD6y6qzggUkAHnbtp85ncSuISb9wECPGBThCpeAAAgAElEQVTnfb+8j5LPqSYK9+9xUkEUVK6nrd8XGRhh/I3j+jJcG7YRFAIJEGhUvB03kB4SUZW+fEhLkQRA7yQOmG3ZgQoSDFBQcGJ2S/vp5uVnjKDyxA/SUjjH8moX78PmCQyejDhXURmqZNlriQfhUWZcXN6HOcG86nvaO2eqgLzaFwUuazeO7iypARUIDlQcuCM+et4eZoEjAi4cuMa2dJUTaG5O5rhhIz4eqHDZ+bHTXhV3Xt7HyM0dbYUA1gMOSOr5vTlXUWmq8/A4wHpz3Bw1GbvarBO7hx/JLph18WqX4wZ92CAxqOyjCogefChGHDesYjH7UMGG0LOEpAWvTnMjPq5GmBfhcdGaJdZ4HzZk3kXF+yM9J+JwIeup58knooCUOW6YYNhr0U6m2v2kMOKz1Qi2KoePenPcwACLG8PBABEeB3y9OW6YfLzFzMy4osGGHUyDmMwp+TJSfQQjP/vZ5734DSOSd3xvwEg07ojP2yUOWbPnbaxg6i0+Ez0Jo1jVPCp5FwfuiI/EjT3OMgp8LFWUug09xI4blgrfytYiJ7RE4XcITy7w64f9xO7nh0oE95corAgx/goRPgD2OuEjGKOmbHA3/xeHBgnNHmwcKI8LktCRybIh5ZfM7kZCFu98u00qDlivUEHw31Ad4O+Bg49TjQP35IA3RZR5rQ1uiFpdG4sNrgjh7UFJ4MlPnky1Ya8VJD/5dCA+4SFryBI3UPhQgl7PkKWH0PM8+kkbn6AXrttrMu+O61cG1+85Sg/2nEu3d5pBD/acG5p1eTWTQ8ORG4F3UfF+uq/7bLrr3Zmh3iRUvq55Z0oo8w7THxA4VMzQGzuT9djy6hle9h0Kiqlhl5nUsMtM+svgpSbI5BJuTsZL9h0LBRY4QJp4HyWvnh0+UR6SSzlu4MZNFPRRzijeZwIjx/VJDZfT89/GYRtBjbLGbvHvwl82tiEWAmMkAaBAwIEAA0E4qtx/Zve/oqIyVHm/skWhefnZ0lUExgg6ebWLk1SewDhrjd3io38cN1zd4EE4dydHvy8y5SAGROHkQvnZChMYo9pXWVlJr3+6khp2mUm/7jPfXBNUfW/vNCNkmobPepqZYzlu0O/KHfG54zQqRqgC4EAFwDYhRGVh+oZ9IXMyxw27yYMQgqChornj4IkqlRFuxMfNHfdYY7dsIzuYKHFJcGVlpekJBwnkI4gcN0cDPvXXid16MdAyYONO4I4bkFQuCSYio9BBQghEAgdG8oFId5xcXOX+2woNnpDDPR29rLRKCw2vMPPvRBSu+uLfgH/A6lJ//GTDLjPpvu6zQ5VKvu4hK0Yii5tRYX8lCu+d/Jpjf7XvHYz4bDUC/g5KANv9GUZ8nKDh38B6h2IDByepuKd9Z20x7wXHzdHR00EP8X3dZ1PDLjPprb7jTTANYjJv84GQqz4A2TueDeD6NoE/Af838Fn8e8LI0k6EQtGAhFRlZSW9NmIFNewykx7vs8BcE+5rgEQdn+Tx7pSN1LDLTHqw59yQeR83jbTnp1dWVtLfRqygOzsX0c+6zgqN9+OO+JjU8MZIP2lz/MxZ+kO/Rf57792ZIa8PPpaKKxqIqErSj6vl+N5gm9nht+NAKxHfx3n1Golp7k/BPw/mfFc0nxxSNCCZ9kHRZmrYZSb9tHMR3dd+Ah076d8Dbnq4kJnHAvxdwNVyPNHOk6nAql3+NBp7xCyfWGIbOlYHJBWhGrL78uMAqTr2gec+XpJ8EgXqN7wHJIlCvq9zMpsEbohaXRuLDa4I4VVxYFZ+b3hl+IpQrzi8fSat+SI0XpTIn6zwUE9/n7232yxqNyjYU/h7Cr+TG0x2KfSf1+c+TvaDqA1kiRsofChBr2fI0kPoeR7dmSfo09bvC/WA7z5yysjq+AHwMT/26Bg+koRXokosyTAnFURkqqOQh2Hj5LN8eWUU1SxktnFg9jb6KF//dGVok+4xvaRKoOK4ARHmfZTo4XRc3/yNG0bZLzQj29q4P0SmN+07VqU6yYMHwDaCsufDQnaIA5JfJDBgmAXpOnrLUZHEgeDRrpLwyvfWL4+HZI2Om6Mxn/nEiycwiMKjwIjC1S4+csc20romr8LYuPdYlQQG79FEEL5x77GQVPyFIcuq9GmjR9Ou+mISAKq5diUcRAdV3zs7F4UqhQiU+JxwHqhC1v/SsOWhtYUefMihsVYxvggBDsgBpOsjl+4KuaM7brif2g5wUHlfvvNwKLHiuOEezRuYuSNvAzhx5qwJJvEdUa3jATT/LEiNuQmU4+botd5+kGQH0FiHqObivuJAAnCM1Y6Cdd9i3NoQ8cYBqT0CwM6FxWEX/5NelWQHN+KDpHrs8tKQSSBRYP6Hg5s9ced2yLkd1ye5NmFGQs6u2MKV+Io80bOVFnDtttst+CgtosDgCwcqU7YaAb24fx+5KkSucMCIj1cceQWq54wSo2LinhFQ5aBi+NHsraF9B5Vavjdc33KiCaZBTOZvOVClys//73zfIwqC8JJ9x4zsHz4AdrIDXgi8/5koIOhYp/a7AaocPu6TV+HR789bDLipKB/3aXtv2Oomxw2k9khMdZ+2ySQAQSrtvYETQD6WyvbeQGIPB69E3sgSofw7E1VN8kJqz/1NQLr5XgFyhQPr1bSgtCyssg8RBS10OGZv9O8pTA8f7TXPeG+g3c1WYfF9rxsrItjeG0RBld+W2XNZNp++kAT4bWBPkigtiAKpOpQoUXFCFOAtAmUj1mx14Pt6lOlkHLghKm/RSgJXhPAWLQBJDcfN0eb9gc8E9/ZBAhCJeHt86YOdJpg9BfHF5v3HTYwACX9FRaV5z0mMHmsDWeIGCh9K0OsZsvQQep5Hd7T2CfqM4n2hntCtXx43rpv2S5eIQu7DfFwXEYUq8VyKbsvTOakgIrorL9MCUYCUzq46oDID+Rf/LMcNxvPYVQdUFroUbgxV4hH8oAJsVx0gsf58xe5QJd5xw+M++AgQHohzyaAJHphcGbCrMuh5hPkXJwGOG1SYeAKDKCA4qPahcokDY/R6WGY5/DuX7DtWRf768UifoPMEBlHgyOu4fuWdV7t4PyKqdSBiuN/ztxwIkQB+r4nCQXj52QoTvDz38dIqhA332q764n5DIsz70vi9BpFH1ReyaIypurSJH4TjvzAuG8TGUhEFKgyoE2CKA4KMnj17fBIITp9ZW8x9RTKMB49PWGY5SH5MW7+vCsHgFSZeceT3+8DxM+SOWW0CXscNxhTZIxF5lZ8ocGfH8VwPP0iy5xsjyEfSDsEkgmP0HI+yjLTw7Pxj9KrIqg96jm01Ag/KuCweB8gAl6eDZOAZ5L4P/LcQUWgsJd87dxw8Yar5uN4gA2etxAE+7+J8NddWaIAI2XunLS2FeSJIMypotjydj5HjqgIQIqxnu7UHxLrVhHWGVF7fZlqV2eO8J7WystL8flRO+Uzs7zcJCDr2goVbD1bx3uDr1nGD6QJE4SAcqgJI42EQB8k3+sV3W5JqrEsE6na1GGSAj/uM8t7gicJ/jA4UQKjY/mXw0ireG/w9hAMVe7wHe0wvMV4CeEfhnYjrwsdj8rFUtvcGEoU4+ExzPE/Fe49W6ZW3E9PY13hrha02IQrIFRKbaOVBQvaHrXw1nT0iD/cVpHjyGn/9IGH+WO/5Vbw37JYZ7ivDe/ht7w2iaLNKIgpNLLnaau2pDlCjoehh+9XEAVJ1JGckXgVEQSyFlpkhC3cknoMk04WNcpGtY3EYsTgwROUtAEng3j58TCjAkzmLmAs9b41rZ5kl4r4iHr2vfUDQ+f2ykyvcaNRWTdQVssQNFD6UoNczZOkh9DyPbs8TdJBaHsBz8yf75cWNomAihIAaARE2fwQOCOxQCeSkgiiQSqOX9NE8KbJ7erlkkEvlQQAR6Pexeqz5/FNezbfHVPE+SiLWo7pkl5FK4+DzP21nZZ6VRg8hyA8PHgDbLAcS60vz1T4QYxyoutpmOUVWRR1GNzgQLCMI5z3K/P7bgeoHn/gE3SYHtpz4Z5ZhDfr077dmReOFPHH1npBhn+OGs9q20zU3rdpqVd5RcbCrvvyFXH62wqwpHCADtuEevheUAKi24T5i7dqSUAQxMNaClBlrBB4C9jgj9Om1m7TBBOH4LN5PzUf6EQVVs5FLdlWpyl3LXJVteTp/jnFfQcAxuxeBN0gkr/ITBQEUzvttVz9IAvGBg3FA7KaG7iue249mb61yf/m1ffmT5aH7Cok5jIZ4AEhEoV55Xs0HGUCwxvu5eWW0srLSkCvcA95Laqq+eVKLZ2fDF0dN5QzXBGSAVxyPnvZCfaDlZytMNR/XBAkfPoObiEJGjURBgI7vicDXNsfkezUnV/g8VKe7WW1LXJXDjTrxm6HKsb03nrVM6Wwzq+OnfHKLvX/xtkNVvDcqKsITHrj0nQfh9r6EpAKeKSRdsK+CNCH5AQJfaJHRNtbegCQN1i+8N7iSi3tvDGHjPm3vDVul5LiBogwJsw+KNpv12zCfbMP+xVsUMB6T+1PY3ht2AohPCuDGr7xSTVRVhYWRe7z6zZNn2HexN+BZhSoH71/sTVi/IEu4rzflE5qfLfPXTwFzbre9N3BtcfDEJDd7i5rOYX9vgKtyeKI4CUgWIUEincENqTqS8VGJ/Cig7QfPkcS0DUqrixtPCvZS1sYYBz4RB/sEnzASB64IgRKOTxjhffQFrIeet8b1mRUuuuC+Yt9r2DZI+iGxvf3AiSojGDfv99efVNlQG8gSN1D4UIJez5Clh9DzPLotT9BRCeYmUu0smSZ/eUHOV3r4ZGguJlEQlPEXNxFVcWB/mpEKooDQQraEnuopVrDAJWq8IoV/D/14fLQKUfglzStSi6zgh/dREgVja4Ys2B4aIWa/CFElRcDOs9Igw3gJ8X5iwDYe4sHP8TNnjWQT2WIQawRTqPLCiRwBCCoxOFA1sb0DiMLz7dHbjqPjx750+U0rgcHHg532zlWRJ6JPn1cc+XUdvGC7qWrgt/HeTtuUjJOOpRaxR+KDVweIwpK2fUdPh2bSO27QLmGbhOGeQAkAooCKHwiNPbIOaxZJExAZOM7D2domFWgXeWPkSvNv3MUCF4yCsk12sGZ7zdxsEiu4lhc0Csy/gmSHH2TyoBz/Bsg+VAS2iROv8hMFVTmc90BHn6DbJk68El/BzObw3EImyUfWEYUrNvzfABGBTJIHgERhc0FIi+/pNquKRB+Kj4mr91QxF8SoRtwD7toNsol+byRhlu88bAg0rgmIte0azgl72SnPVPNxTWBqae+dSJ6icoXKGb4n9iUuRyUKzzDmzy0+D+TXnl7BVTmQFt/afrpJUuCZhvQeewyq2Pj//8jaG3Yd9NchiMnS7YeqeG/YxK8PMzzjQbh9TbC/gEQg6QKCjj3GVi7ZqgmY9UERgoQTyBBmTvNzuPfGYDbu0/besFt7HDdoM0CiuNfMzYbQwoPg/7P3psF6VdW6P3VvXevWuaXWOXXv/XDrVi0bUFEQRFE4Ko2oh6OCiqJHAVEQUDwiHL2uJCRAQt8EJAESIA0JkBACZKfvIAnpe9IS0pCGkI70ffZKssf/w1q/OZ853nfv7Pv/IPtW9qyadTzsrHetNddsxnjGM56h9e19eUwtS+W1N24VodIsj2wT/Tartu6r0TUZ7MYEAGK/Kw2p/+b48aawNzC/YOXAJACsA8gi/ekL1Xe9qJoXL84q5yUCdwhmapqcT+1RME0jvV57w387bUrLrlfGr7kGqA+LL8vjHtxSg6rO83Kmn6jhoAKCK/DSXCPV47ROY2rSQ1pqWnZR2U0nasoI4QxR7QRYE1meMgA0NY797NoqGMQ4YVd9vVt00D8vUXM958wiG6a16vp/j9aWfIP2VrZ2B/0ka21pERZFYf/ctXTQifpiKM1dtzMpC0Yn1xCK76bdh2oo6B6lxxnQOrJmFoTUcPQwcMkdJ18YWjkRPQ7pK3vNTAxcHEfyfn2O9eOSV6nRfF9HWvMozWJU6Nmp7yaCSRyktG87g11RaYxEDpt6qq4+qmBmSbSP1AGMYij+SvszixRODBDy4aBgYpRhhGtdW1WV9rTGzs+WDrpXBlanY+/hIjix3I88fc0zNYv07kcnrAzfWHNNDzWWkfcviBFuloqIYahyL8ZVowM0jfZpTXp+yywKS2GYaoRT3xNBQMAl1TswizRZxMYwFnBgGHMPdhDhvLbfnDAm3CvLo2q81uA2i+yQu0cuD5FrjVYijuPBDo1cMe8BDSi7BZWUiKNG+c2iAcV1F95dGkmTHTNFacE7DzSGMcERwcjTknVmad1djeZDp2YeYgCijaBOn5Zq9BR9cuhHL9mcOFC7DjSG9B2+garGYxRSlpC5O3319hDN591Yi778X1NTBI627DkcovlchzOoTrGZ1dRyBljjOUk/8WBHYNv0TPU8uB9CfL7MlupcaKUDwA1YOUTGcPT/Ivnkx443hZrZ9EUbyr0Sx2T++l1BewOlfaJd9O4iSKXUVaL8gG3sl/x31jBpBYBunjXh05FgH+gcMov07dFLNidMrixPtTd8+guOyMqt+xJhNTopXwoUK3376LHjiRq8L4+JPsWIRZtqHBEtF8Z+QdN0AV+Boe+0NE0K4EgFKb0Q44EjR8PewDzgjPJsOlg5VJDhu36/OkP7TC3X+AhXjUXT5LzQqJ6jWoPbn1dmzTvoysrxFRdaathAWnIUMcuWGqkq2Av1mHb1GuABjAVAypaalrr7mStl2VIDtPzd8/PDuafVLZprmjoIOwTmmNfDIOXLLKbGTXpnW7A1GRe+K/PsXNG1UHaYCiCaWQ1w1RZaW/IN2lvZ2h30k6y1pUVYFIWdVznoKN+qkelznrM85sdpLV9f5guaJp18Iq0jaxbLIpFPxGGLgU7USWltZpHed/kT05PDFjSViLkKHZlZQo/SiBQGIA6Jr+35Z4lkeKofzr9ZzKPkfRWVJlcK4+lLdern+qiCjsnCDbtCxBB0HvpbACyq/98bIOQI823JK0VjQEu+qcPm3/XWXqWDfqsDMNTx0vxnHETYGZpnapaW3VJWBM72xl0lBdnnj6nDxlzh3XAiNTpA02gfTiagCk6kdyqbmprCXMeg4d5ZHh0Rr3cAdfXzXcZaU1N0TDCQmTce7MCBuqzntGTe63ozixUDcDLD3H4pRt5/+MT0RIjPrBbsUJYH8161J4pjx2sijio0ZhaBKJw6xL+8NoKZVn/YFwwo7ocT6VWWxwtDRKP57E+U5MPowzlVETeAl3/929Qaij7rgyoOgI/v7z4U9Bu0njZRt4uqCOq8qqwX0cIJy7eGaL4Kb+45VCQRR1I/VHATh5frEP/CKSb1wzuj5A/znIiCebBD92pNTeF+sHJ8iTTA1a/d+3rQb/jmg5MCjZwIuVdZVl0AdTKJPk96u4zY4Zgs3LArvCtgxOx308oZnBdmluQue+0NUq2YT1leAkMqUGaWRoEPNR4L84q1wfzVOWQWAYCBs9YnGgRZnmpv4NwiFMg+OHPNjrDna4eBpfusghvb9h1O9nxfHlP1KTyVV4VAszyeBbo23/1gf9Af4QwGtEA3AoaAApjeydq+/0hwrkKkswIKPM3cs3L4rj/rXa7Nnq+XDqfPjdc0Od2fszyKrZql6W1mETBdu/1ADbiiCuKdRCOEAALMm5YaNhCAa5a3rsQX5y/jDRh0ouYZWg+OPbFom5a6w7Z4ZX5tfXHfVHNI2SEnasoI6eL0Qnx6wh1SzUC1fSh1iA3Jd8WuOqtLdNA/I6r7ur+YWavLrv49W1vyDdpb2dod9JOstaVFWBSFfe2u0kEnqhnQyhXbatD2LI/0OxUHYtPEePRKseQTaR1ZM6HzVlFHEGqi1BhQntamIi+ah4YhBP3OCx1pLqtGpLxo0B+dQnJHoc4iukTXEh2+Dq+i0jgvGI31RGN8VMEsFeQiYsPhBk1+uEsxMItO7brtB0KkD2Max6denWKNZHla428r8a9bHIChYmOIcZ1557hgLFBSTPNMzdKyW5rXBtqNGr8XECLN4Ge9ZwZDRtWhDzYeTaIDNI32YRDiUMCeIHqnTiXRCQAm/Y5EvnGQ/1yBQ+r86P8m8omxjlMM2LFADBB9T5w4It+hYkCVfw3171d95yQAhgrxmcWoAmCH0gf/XZgi6gz4iKPXnCB1gUgh4l+eWWMWndrZ7+4IZYtYl9A5tWSdWVpGUPOH+faMORF86J2aBoAuw/d7TK1xBvh30Ds1DYAIkepqwOyIGhMpVX74ok2JtoA6A16vQefXsk17grYAY4L4Fyr0RGafd6re0JN5TkA3D3YskL1adRm4H2N+nxNjUlaORleJMGJoQyt/vqKoEuHqNnJ5iBZ/8a7x9m/VWL0yr8wtxjFZvHF3+MYo7XvdD8131dJXXntDy41pSpYKlJlZ4lzvPNAY1iR7Cs7AZJlDZlE/4m8TVyUgJR0AxkcZVXujnoo7uhZ+n+Ubr9iyN+z5//b0rASI0N8fs2Rzkh7QePR4OBPpMH7M0nSBtU4PhfQwQFeYHTqHfOnS93YeDM4VKUCMuWfTeVYO3/U3VST6obHlfx+2sNzbAGE0TU7LYuoz6e/DrsPZnr9+ZwIyZHnqSOs69oBcS011AD7hhBRbathAzBnNo2+pMTeY88qMaK6R2vH5LmNrBBZbalpHXtOPTtSUERK+R/W9PVAF28Qs1fbhmT2bizVw+u3RQQdo3bznUPh22GZePLEttLbkG7S3srU76CdZa0uLsCgK+2rloBPVjGj8luAIau8+YWVNDXMvsqPRJjXWMDIvqGhzGPpQCMkZxUnC8PK0NsR6vvXI5CTvTennew4WNQImGLU3DJiX0DTViDl2vCnkTSJgoqVqhrq6rtzXLFJqKVWiqDQRhD9J6R8iyyMXb7J+09eGPFnyTM1SQS6MHc1rGzxnQ8jZVMVXEOP563eFKCrjgRLwfS6qYGbJQea/Y5aPsikrttSUeDKzYITgVF708OQAdJzTbYItfX9Pzfho2S0MklsGLwzv+fOnZ9p7Ow/W1J9VemeIoo55Oxjhd41YFgAYpSRrtI9x1YjS87PWh+e/XHJIMRAmirAc3/GsruPttYUba3LxtPybquEzB7O8NOC9qBbO8Oc6j02McCjMT0xabW+9tztErZlDSv1TowljHVaJOipmEUQauXhTItxDzt6Que/VRBx1HPYcLIL2AkBalo+y5Rt31Yg7mkVneMySzWF8WN84n1qyrtw3olCf5gsrgHSw8WhguuB4qzo7e8plPacF5s453SbY8eNNNekCAERLNu5JxNG4F6rdPioDs+WluRsSOmcEvXbWlP8zS8UkAeF0L9t9sLGGcqz1pQ81HgtrnHl5WqcxtmXP4RqwQ/dqjWjr/fYeLsIYYUArK4exvPjhyUEv5LROY6w4djxElRGpU5B0llRIuLkqqfT0lBJMwTFZ+v6eZE/ff+Rosmbo5POqUr8vu6XlxiJ9e1+IKisF+jRZF+zb7A2f7VwCBTqHzGIaQJeGpTX07iwvHfddBxoju6ZyhlV7w1evYD2Y1ebz4xzPWL09iSTDHCG1Q8tSqcDe1r2HayLoNw2MkU/N2fXCkCpaxrWL3tudzCEfiV65dV/YO5WNVRw7npy/ZrWsHL7rHyoAtduIMqIKQI4+AQykJyevDnuDplEgXsjzk5IG22X8si01QqNaG17XMeM/SxTGm2sqPMmeC8DcUsMGgkaOrXSiBqjIGddFItDNNRWlBahWAcbmmuqt+CoRZqU+whOTVtsTk1aHdA2zlBECa+qsrqWKP7YP/RfPRFuG82X66u0J2+Vg49HwXdmfT+0QHXTVnIENA3jryw+2hdaWfIP2VrZ2B/0ka21pERZFYefeWTroRDU1CkSNZt81ar1j/5EakR1+A0QewwEjk3w4pfOaxUiSqof//oX5NbQ2HP1vPPhGkkepgmGPjH8niKBxWKnAiNI01fjcd7gIh9yAiqap+Wv8hhc7Wvr+nmCIcygpKs1vQJmjQznN8ogCa346h1rvKWtCBHrs0i2JEULJEj0kiYyqWjmOEGJ4PqpgFumXalBpfd/Tbh8THBFVYIWCDf3tx09OT0QGL3xoUiKiZRYjo9999M2gcv/XoYuTWtDXPze3poapKgzfJuOjtaAxgj8vYnOh5vj4dwJFfOTiTeHZuR+/TYM+p8Jy/jsSuVBEnvnMPD+10+igF5DlpfN7sxPR0pxO7nfVs7Nr6lz7igEaeQ/MhBcXBCOftcpYItwX1N/nvZfQk5kHn+wwqibiqE5F9wkro+MgRtblPafVKEGXayJG+zCgANyI0PucXWWWqFE5SWpB9522NhjrCA/hLL4we334Bj98YnoAg7K8pL9jrJMucLGkYvSWShAe3CDqS5k3/ZZK5/yhOAPeoTFLI0RaUoj9c80H+2uELBXEfHH2hkBP1nn59QfeqAE7tIycKoprFYWeb6yqcWjMIvsCQPBbj0xOQJIxSzaH74tqOwDHrS+9Feb+FU/NsM6vlY7PA6PLSB+OybJNe5KyWxt2HAx7g+55sB3UCA9MqKrslpYb029FTXkV/MOBX7V1X2CnKGhx4MjRmmoZsA5ufnFBcobg6LJ2fTURZWQRSdaOrgXnEE6TMrJUhwNnB70AnUNmqfYGqVZ0PTM0Z9fnlqPvwL5K1zlkluZyv/Xe7uBcTV31QRJJXuDYdJ6Vw3f9a8WK6fBKOXYA5IiEqfbGOkkr4hnIMcYho8ybVhfAntDvR9OKLl7ktKWGDTRi0aag+7GmFeXZODPY++tp1dRr3IModWsiwypK65lcLTXVW1E9ILOoV0I/S0AwZYSwJrK8tNtGO5aMUvs1DaupqSkB0/iuHWXfO3ykZEAoCwzQP8tH1TxLW2ltyTdob2Vrd9BPstaWFmFRFPblykEnqknu1ND5G8OhfO49E5ODHYc8y8vojhfZIWqHQ4nhAP0ZIxODHrxFa/EAACAASURBVKq2Km1ygF7Za2YNrU3z1zxllFzMPw1eWCOCptRfjUhpjvC2fYftd1V0ByVR3r1Lw9JgkF7Xf24iNDZmyeYQUaNUjKLSmm+vB1FvOahwFLTEmCL4SqlVZ5HrYCKYxSjKCDEyeWcOzXpGOHnaKgq0fNNeu3fUsvD/89vkmZrFyCzv8/OnZ9rmPYfCd/x8l7E1pXTU6dCSb8s37Q0R4x8+MT0Ya1AE1VDWKNN0ATuIihL19e+rJd+YX1keyxb9RMRjMPRV8AfAxV+HaJdZjLDyDT7XeWxiyD8y/p2ayIX+nftd3Wd2MA7pGC1oR+iaUEqtCmwtfX9PIkimc3TAzHVBTPD5WesTB5DfJuKoDlSXhqVJ6sLdI8t5cv59r9eIF5qlTge/r7Wgjxw9VpOzSwT/C3eMS4xKzXm9a8SyAGZhdEF57/nGqgQs0Cj2C7PXBzCLdAEcnDFLNieVIM4WJ87MakSjVKtCtQXUGdBcS5pqVVwuJYUuEMFOX/5PxTGfmLQ6aAv4eenBDt2riZJCo8ex+evQxTUOjVl0Yolof7v7lCSi9fSbaxJauVlMV7hx4LyECdV9/IrqXmVU2Stkq/YGUV9VIOcbs29/sO9IDdCqNGPW+6R3tkkFj5hKdJ5UL1HA5DSJfvpqIpwn//b0rET8z4NpvpqIshPekrQZTRUxs3gOVfus7hVayYL1TolHLUule/q0VdtrSm5C19c9/P3dh5KqF1v2HA7nEA4rHVr5p6pI+2QBzWas2Z4IpwJqv705lvCEEaLihfpduw4vWXx/GlTOX1+VQLU33pW9gfJosHLQQkAEUcULvcbBaZIWpesY1tLkVpQiu1J0AHwpwpYa/xYA5lxJd2upsf4B6G6T1IXmGmfDWV3H11QTaan1Fi0fAgyUHuSsUNAbYWE9q7Vc5pglm8NaggmgaX5e20eFTvmualft2n8oYXPs2H8kCVQcO95UE4RpC60t+QbtrWztDvpJ1trSIiyKws65o3TQY9Q3UhS1DqtZVApWxLme8BEOHIcUxqE3Mj3NTQ1gBKa+32NqDY1K1c49ZXSoCAVBQSQfE2r0T56aUQMWkLO9fseBmjxKIjj5K4uTXGkzC9Hr52etT0rUmaX5xd1GRudQjQEMiSwfFaINSmvrKCI1nlILPZrrMFrMYrRFc+aJnmV5SRH1tZTNYjQPWiYGQlEUdmqHkeGb6PiYRXokwnywHSiL9YkOo2ocGoy0Cx6aVFPyTVWjeWaUyFV8zEeZoAZilBL1NUuFgnw0hLGA4q/1Z3E6NPLKe9K5TmvKQ+mHjkxkhnft+NqSWMKvGkt1Ornfr/rOCU4jHQeGigFaNrC3qxXLu05Z+UECRJnFvMBeU9aEufzi7A0JRZ9ItUYclbqsaumrt5YG2mc7j6mJruic1bHcvv9IMOg27zlUk7OLIv+nOo6uqXTAPL1l8MKadIEHRAQRsID0DhyOHq+vqjG8dU2TupC/sjjJkzZLy7iZWSJ8pHROdQa2ybvQtCyWagL8SMS/fIkvs5gf+/jrq8L+5edlHwd26F4N8IGQIvnq1z83t8ahMYvOAwwNnkXTTJRWbhap+NeINsIvn51l/aeX3/i3Ve6qL4Ok2hta8o11+sDYFTVGuFmqvUGKQ8Nb7yfpRvW0PpQ1ofXt2bPeem93TTURZQDpuJLGQffVRHSvUyaXr+gAYEZuuTKAcFR/3W9OcObYcy+XOWSWam8QbeeMJgfcLM3ZNUu1EZjDXpeG5z+1U5zPOofVuVJQMZy/FZtOGUD6XR8ZV+7ZNw4o54mvSqDaGwB9Z3UdH5x1WDloJTxaVQAAyOo6YnmwS7Q8KOknCvp5pk1LDeHJMUs2B7sAYLqlBohBRFnTMFpqsB+wM26WHO7mmjJJwtyacGL1d7SD/vzyopr0Rhgh7BVZXtqIZrWMEF2TgOSwsQANzWq1fRijlVv3JSr73G/zrv2JHsKuA40J63P/kaM1525baG3JN2hvZWt30E+y1pYWYVEU9qXKQefwYBPtP31tjegShv44Kb+173BRI7KDM8FvkU/kjUwOCBTNQU/XfLA/5Ct+65HJSbTALNI0P99lbJI/3tTUFJy37z0+NRjoiKCRp3tZz2nh9wELOFBWbNlbk0epOYREj8jd0/w/X8pDUWkccUADOs4ARpoaLWZpmRcPAGA0EbFRwTpy4JSCuu9wkUScutQxwnFWMCoRTyuKwj7XaWT4Jjo+ZhHVhm0AmKIpCETgGB8VF9Qa9WaRXaE1wDHCp4iasj9omSs4U2rgqCie0ubMojOHUYregVl02JSW18eVHQK80pryGBsoaRPNJ3p808D54bcxwtU45X6/6T83OHF+LIkqqOPqI3bMBQVrtldjiWH26ISVgd7/0tzyu+KAYgSrQ6OOq6Yu7NwXlZShrap44a0i0Ma/232wMYz70vdj3jdRIGXJEKHBIFRAztfcxtH/46CFweAFeHlAaMGovZMuoGu6h5Qz81UIeGYiY/cJ3VYplOoMUF1AHRpNhQH8mvzOtvDfX5i9vqYutf92MBr8vPTl/3SvZiwRUgTE+NGT05PfprG/AQDxLMyFv7y8KKGVm1kY95/2mpEArcMXlnPjiioa7dkJqr2h1Sb4Hn8durjGCDdLtTdITRm+aFP4Hs+8+W6NgrhZWhJTvzPf440VW2uqiaAt8eW7JyaUcBxruq8mog6ORpLDXl/tx4DlCHfhhHR6bUlwVK/rPzfsh3wPLUtllmpvsAeybyLEZxbTlLZWTCXO+zdXfhAiyT4CD6tAo85Xiq6FOleAxsMXbUrOd7NUe0O/61OTyrG7pk+5H/uqBKq9sUrsCRV+O3L0WAJ0m8Uz/U+DFwbmFedvlpdOnFmkQveZtrZGTLKlpgKVvgxeSw0biPdCpO9EDfYD36c16uTKJAFku3/MiXOyVW8FRs4nO5SCfFqp51NuPnlGiDK22BsAkzgXzFKNDrMYKFr6/p5EZf9z1R64ZuueBOjec7Co0U36rbPx2kJrS75Beytbu4P+d2pPPfWUnXnmmfbRj37UPvrRj9p5551nY8akStozZ860iy++2P7hH/7BPv7xj9uFF15ohw4dCn/ftWuXXX311faxj33MPvaxj9nVV19tu3efGBXV1pYWYVEUdnaX0unC6SOn9+k31yTRNbMouqRlaw5UB5nmBYE0g7ZjOPg6sqrIbJaWG1okpXY0WmBmiZHrKaNa0xzDGCVivb8vDadOhs+j7C85vb6siOb/nesMdkWltdyQGjgaIeZ6VW5VqqkHADicuO4GOZRBpwcKLftwcSwYwiu27A3PpzVTiX5AK4XdUBSFndF5ZPhvOj5m0cBmzMkR1IOSiCw0VtD28+57PYxj1xHlt4Klwb2yPBrh+h1vcA4uUVscWI36KgjgnS1UXYnAqeAehoVGJzXFIMtj3qOWh8HAZc6QWoAQ3ZW9ZgYnTMcSUSfud/1zcxMVcR1LFIWJGJ1x57iE8WEWqYUqLshYKqtA89HNYpkyHH51aNTJ0PzexsZG+3TFtMCQU8EfooQ6lnsOFYkz0Nvl7KpCNoY99GRV7vYRGoy+q56dHejVgAXqvHNv0gV0TSOC1um1JVE5v3J8APWI+vJvO762JAEL1BmoV11ARRe1NBwAX4/XVyWgFI095eFx74Top5+XvvyfWdyrGUuEFMlDv+ChSTUOjVmknfPteBZN+1FauX6f7/eYmgCt01aWDggU56icX+bpqtK+Amsxyj8vmRd7DpZRustFe0MFEDXKr/sOjYjn6CWbk5SNa6Q+t68moikCqmbutVs0fccsLVOlkWSvnO/TBbjud8/PT5hcAA4AaJq+Y2aJ0j7rnf+W5dEZ/aRj1wDsDVv4fgDWNK2LfVfnkFlUVn953nuJcwVFv78IonL+KpCrYMeAGeU6hfniqxJo2S1lEWl5zM17DiVq7GYpsKdMCM8w0nWstPUTNRWe1BSDEzWAbp6pXrWXeo31z96v6W7NNZgk594zMawxzt+Wmp4vugZ3HmhMKvWoPWdWywhRhqFqC0DXJ2ffa9doqpx+1y91K/eQZRt3JilA1LrXCib1zt0Pu7Ul36C9la3dQf87tREjRtjo0aNt5cqVtnLlSuvUqZP9l//yX2zZsjJiN3PmTPvYxz5m999/vy1btsxWrVplQ4cOtSNHjoTfuPTSS+2MM86wmTNn2syZM+2MM86wH/zgB/9Xz9GWFmFRFHZW5aDj9Gkt4dtcvWsopFqqhZJDqpKLk8dGjuHg68hqHpLmQK7fcSCJCGq0wMwSoSWMpE9WIjWIlJx2+5gaJWI1hjxYoPXfvWGkxpA662ZR0fTfBy0M+e+UooNudv+YFQnFTg0cxJ2yfFQ4nDFa/G/4iB1Rea5DqdksGkkaUWs8ejyW3Vq9PRjhiPiZxfxFIv2I+CiYg2PC+JhFZwVD+Dqh22M80HFotNauCvGZxVy2hCpXGeEYd9/uPqXmoIVBwT01z1Sppb7silKuMdxoiH+pDgNOtu8wAMxiVI7fhimi7IDfuLlmFhWMud9vB8xLxN60U+JLWSW+vCAgj4r2MZbdpdLBr0R/wiyCPHxTdWg0yq2pC7qnMD+vejaOJdRyHcv9R44GZ+C1hRuD8w8DwCxG94gsARaocrfXjiBN4tK/Ta0RmoQWfNWzsyOluWJTaE6vCk2irTG6KhsJ1ZKoL8DCrS+9lYAF6gxo7WE/Jk9MWp2kXmiUH0dXy/+ppgLj4+elL/9nVhulgwZMfv8Zd4wLhi815c1iJItvR/4yUdQfPjE9oZWbWVRuf2RyYFT8pv9ce/v9XWH/M4uOCca8lt1SEAma+Y+fnJ4op2OEAzK9NHdDUm5Mo/yLXGqVzvWh8zcmTqWKdPpqInp/VQL3pcwYL9g1Og7K5HpUIuT6LqQLcP8re89MyuxtqkCfT3ccbU1NTTXpO49KSs3dcp6oEJ9ZFHiDXYNz2mfa2oQRou/Gu6qwmupaaO1wgItHxr9Tc/42NTWFPVvH8pV55dn7/cfLuTbQMdi07JY6nGZppFXXmJklTDsFv04XJXszS3KVVZn9RE3p8AB7pBy01HBOsVU0FaalRrSa76MMsOYaZ+zX7n09OQdO1B4XVpFZ3E9Wbd2XVOrx9opnhKBx9PjrqxJtAdXeMLMa7RpNqdLv+vX7y3No7rsfJHoUAFCaRuPB6LbQ2pJv0N7K1u6gf4jtH//xH61Pnz5mZva1r33NOnfu3Oy/ffvtt+2UU06x2bOjsTlr1iw75ZRT7J133mn2Ot/a0iIsisK+WEVFl21K8yi7j38nIJwI8mDoa4SAWq8qsgPFDscaw8HXkT3gSmZovWuthTsolI0qUXNF23FMoIxqrhFGJirlmvPuwQIVZ/KGkUZ+vIAVuVO/eGZWOABWVgb7AxIVViqWGjjaccyUxqpRFZ+niVOLYYNSs1mkzSqV+NjxphAFGLFoUwLG0KDmYRQT4SqKwr5SCQpiRLwshxt0aOaGUuw4wOk4NNQ+PafbhBowhfQH7pXl0QhXcTl/0M5ygj8qsqOGhdZ7N7OaUk4agcA4JcrwiQ5pyTXt6B2YxWgezgFgAe99VtfxwSnWsWQdKB0VQ8R39AgApj5z+5iafH7e+zYR2WIsVWHaRz95b4A5dWg0t/lcyVUtisK+3q2cJxj4CnYACvFurH3+7bNT360pWWcWHTiUtQELeO9TO42uYVMQKf3qvRNrhCaVFuzLJ+G8/+KZWYnQpKdvR1CyjPTAVrlp4PwELMC5/t7jUxMghaZaEJp6oVH+ejXlWTP3jn47RD9V2T7LY8RTx5K9mrEk9UL1PHBMVTSKPG2+Hc8CTfsbD75R48QAoJx/3+vJPr5194Fwr+LY8bDO1+8oHXQtu6Ug5VwR96xnhMP6enLy6qTc2CCJ8mtqDY3o3sBZ6xOtj24CFHiQxyyyvnCosjxlLbEOszyya5TNoZFkrx1xjZtvsL4u6T4l3ON3z89PxkHLHs6oGCEDZF4C6jw4dkUixFcvnx+GxkPjVoT12delUPBuSsVWYTVl16j2hj9/zWIKhY7l2CXlmMMq8ww2zf1nblBmT1k5WlXBzAJIc959ryd6N+dIrXkzS9Yx3+PVBRvtRE2FJyPd/cSRdwACFQ8kBaGlRuSfc+wKEeZsrmkt+np7bnNNWUVmMUd81rs7kko9nppO4IMUKl3Xqi3wIyn1a2Y1qX1aNURV9i+p9qep72xN7MCDjeXeoOvar6220NqSb9DeytbuoH8I7dixYzZ48GD7yEc+YsuXL7dt27bZKaecYj169LDzzz/f/uf//J92wQUX2LRp0Rjq27evffzjH6/5rY9//OPWr1+/Vt+7LS3CoijszMpBh3aspbd8vWuojVpqpfFoqdB5sYjBQNPEqMzyEpHmIKSsmuaabd9/JKl3rVFyUHMo3Bq5wNnRHDioTDipqJSrONAkBxaQ+/Tqgo01hrjWo/YCVm+KoX+2sAjMLKnDrlQsNXDqdTValPrt8zR9yRxUfM2iwan3a2pqCgbH02+uqdEYMLMQdcJpIB++KAo7765yrhCt08ONQxRHUuvrYnjRoa6pqI8e1maxRquqwWKEqwK/j/ouEsNGjTUzS8SavOCe5mdneSq4h8HJM36q4+iQj+o7egdmUQ2ceQBYoGkZmh9Ow1nhfr9/YX6NOBMdowUmyamdRtfk82O04YBneUxNUYNXxcrMIkODXF51aAJN98UFiX5DURT2L/eNsCyP+YQKdgAA8m5ZXoJ8OAMPjl1RQ9E3iwAQjhZggRpi3I8IDXTyUzuNDiAb9ZOJHp17z8Swd5Ejqs675j+zdrpPWGlNTU2B/fJuNZ/1HgoW4KR+5vYxNTXlzVIgT1MvmJOX9ZxWt6a80lIZAy2XluWjEq0AGu/LWCKkqMrdzBUEy8wiy4hvx7OslfJWWl6qXOMRjIKefMOAeXbkSKN9Ii/3k617DwfHhFrRRJmv7TcnzMMHx64IUf4sH5Uop2OEA2h2G7k8KTeGbspFD08OUT4Uvs2iNsLTb6ZOJeP3H0MW1YA8ZjGaB/39Ex1GBcYVnXnDelSwRSPJON0/fnK6NR49Hr7BsIXleuSsO7vr+BomF3vG6m37E+V0s5j289NeMxIwCCfypbkbEm0C0l8Akzu8urhu9YUsj7bAmTKfVb/gfGHXqPaGB+vNIuOI583yUSEV4tMdR9vBxqPJvmNWRt7Jv0bvAOE79rPXFm6sSdcLTLtOYxIFec4F6NS6jmE7qTjq/iNHbevew0Gp3L/L5He2hf2zNZF3wFlslSyPNpZZafscOXosuUbBFfYgZdrotdqUSeLtGrNSr2Lr3sO2de/h5Bl8+VqAsNFLNifiuwAkiOr5wIeeU6otgN2GlohP7VPghe/ae8oau6wKDI1e9H4S/CGIpOCnB6PbQmtLvkF7K1u7g/53bEuWLLH/9t/+m/3n//yf7eMf/7iNHl1GXYmE/9M//ZP169fPFi5caLfeeqt95CMfsVWryujivffea6eddlrNb5522ml23333NXvPI0eO2N69e0PfuHGjnXLKKbZjxw4riuJD7QcPHrQv3F5F0DfutKIo7P7RpfF1R8MS+/3z5eHUd+oaK4oi5IOpovShw0esKAr73uPlpjlx2Sb7bmXITVmxJYmA/q5yGi/rOTU8AwfS2m17QwT5vR37bO+Bw+E6hGJuGDDXiqKwxsYY6Zm/tjRwPtt5TPjNf66oTpf1LDfsB0Yvt6IobMWm3ZVBOs7GLy2d7st6lM9ybd/ovPysd3ngDJ273oqisFGLNob35lluHbzAiqKwt9aXEduv3D3BvnhX+a7vbNptRVFYj4nlAfTnIW/ZX14uDUD+W0v9+4/H8XmwipJ3fm1xcAj4/b9NSH/rjy8uCNfdVI31Q2PfDoZjURTW4ZVYJudX1SH1xBsrw3W8e8dXy3/3rUcmh7nyjSoyGoyBanyKogiGzS2DFoRvzd8ucmWHVm0pn3/VlvJ7fOGOcdalMur4Vhu276sZlz0HDllRFDbn3dKB+voDb9gvKweXZ1n+flrT9rz7Xg/P8cQblGtaGKKIC9Ztt6IobORbqYN+Xf854br/GFICVbdXtZtP7TTaGha8V/fbdRuxNFxHXut9VaTza/dOtKIo7NDh6KCzVobO2xCu4ztzv5ufnx9+w/e31pf7yKad+8N35t/e2bDEiqKwEdW7/Ut1rywfZXsPHLaiKGzQ7HVhLvy8+vbDFryXzC8iE9944I3wjKhw3zBgbgCOlm/cZQcPHrQrHh4R5k6Wj7Jf9Z0druM7825ZPsoOHDpij1Zlt/7Py2/ZY9V9/zp0Ubjugorx0GvyqvDt+RviQEG8cNZaK4rC9h2Me8jTU1Ynz8L8+nTH0eG3Z63eVrOmKS/YdfhS+1M1t1lrn7+jdCpXbymZAwif/eSp6XZd/9IYfX7mWlv3wd7kOvYgnv9RKTnGWpm5epu9vjw6KjdXtOEfPzk9XPdAtVfrWM5Z80EyPx6u1r+O5b/+7c1kLM/uOj78DbCFufLUpFXhb5dWhnGnCmz80RPTrCgK27E3lt2ENTJ8YTmHePfTbh9j/aeVEeIbB8xNzp7vPjolnAPrPihBHiKnP+gxNdRMf3DM2/bBnnivvw6NjJB9B8v5/OSklWEf4lnGLnnfZq2OzAL24gsenBTejXrb3cetCGDQW+t32Asz14Z5M2ROBXQ9Oytc96Mnynv0nVq+26c6jraX5qRO7BXVecl6fPOdEiz4dvfJ9sbb5Te+9LE3bfDseN3X73/dfvJUed2r88u9YfOuuMZ7V9/u5hfmW1EU9o1q//3y3RNCRHP6qq1WFEVwci9+eFIYy4fGvh32/ywfZbmcC9v3HrSiKOy5ao1f33+O3TigdJr4hv7dzrorzqFuI5aGvVDHkj3zJ09ND+fvD3rEs+6qyqFmLLN8lM1ZHQVpP9t5TJh7vHdRFGEv71c92z/fX+75rJmnp6wOa5f5rPbF0Lnrw9z9dvdy7N58Z4sVRRHW8Qsz19r11f/O8lG2Zdd+W7huRwgqXPjQJDtY2UJFETU13nh7s13TpxJsnb3uhDYZv4etkuXx3GOfYGy55vCRaA+xB32n+5Tkdycs22Sf7jjaBs5YG/7bXDlHGbubqnO7sbHRvv941Mf56r0Tw3MEm2RYOZ9/WznU/ae/G+batx6ZbD+s1kaWj7LFG3ba1dX3HTJnfY19hG352+fm2p+HxHW9bc+BwNBatKE8635QOeLjl24K37XX5FX206eiXar7xP5D5XfBgR+3dJP9GwGZ+RtO+E3+Xn3Hjh3tDnoba+0O+t+xNTY22urVq23evHnWoUMH++///b/b8uXLbcaMGXbKKadYx44dk39/5plnWocOHcysdNA/85nP1Pzmqaeeavfff3+z97zzzjvtlFNOqemDBg2yhoaGD71/vjKSeg8q//+beg63LB9lv3x0hF3+YGlo/7n3cGtoaLA7+pR/+9pd0VEbNqy87uJ7qrzTvsPD3x8eMNyuenRE+LenV/e68O6RNffvNaghRFQGvNxgrw1rCNfd2LP8jR8+OCJc96lKiOqRgeW/O61j/E0cSRTqb+hRXtf3pfhv7+5XvssF1bPkTw8P9+O6zs+W731v//Jv3+g20v74ZPm/r3yk/M3nhpS/+ckOI+2zlcr5M4PL5/jTU+W/veLhEXblI+U7/PuTw+2vcq96/Zvd4rvo9+D3n61+/5an0t/56cNxfH78UHm/6x4fEZ6voaHB7u8fr/lCxZ645anh4brvEP3sXv7f8+6Kz3LRPamDzvg0NDTYlyv6+4+q+/74ofgsX3eOfZ+XGmq+x9WPldfdWH2r54c21IzLy6+W1z3+Qvm3s7uMtG/fW17XpU/5LP2GpNd96Y74/HyPnzw8IqR2PPFiQ824ZPko+8ED8fn/rRqLX1T/99QOI+3lVxvs/K4ja57xN4/H63i2a/82ouZZPlN9S/K1eX5dE9zvxw+NsEcGxP+uned/QcbrN9X9fv238llYI3zvLB9lQ18rr+v8bPne37lvhF1yb/n3O/uWz8I85b5fvjM+P3/7wQMj7PTqXZ6u5uXV1ZqHnfM9GUvGgnfL8lH26rAG+0vv+Hu/kznPdbA3fv9E+bcvy1jyLblfh2fiWH6yQ3odz/LSq3G8uP6x58trnh1c/u2znUaGsfzN30bYXX3jHDm7y0g7rePIZD7fU+0p3+w20r73wIjwLLqX8Q0+f3t8ft1TvnxHfJZBr9Red/E98Tr2RR3LF4c22AV3x+/MeOtYXnh3OiZf6Bx/89w703n5J9kb2FdZDxdVzzJM3o/r76rm0MCX49/+o9fwsEc0NDSEMTq908ggLNh/SHmvhwfEs+aX1Xy6qecIGzasIVSTYM/J8lH2SjWfmUeXPTjCvlk97739h9uQV2uf8VyZz9dU+8/1PUaEefTkiw3hnPhmt5HW8Znyf//r/XEsYYv8ofqGn+ow0oa82mDnyd7AeXhttR7/9nxD2A/Yd77ebaT1eakhjLt+gzuqveFleQe+3RXVnv9LOWcpndp9YPmMPav98qwuI8N5fFPPEdbhmTifvypn+uBX0r3hu/eNsB9U3+ovvYfbDT3ivfgGOp/5+zWPpWPJN/3qXSPDWrlAbAHsDcYyy0fZS682JMAwc/sKOesY33+vrjun2hv0mwIa6nzG3mDOXHj3yDBn7uk3PJmjHZ4ZHp4vy0fZrb1qz3H2gYaG+P0ffG64XfZgHLsT2WPYNZyNWT7KBlXfQ++V5aPCNa++Fv92TzWfviJzW99Vr3usmodfvmNksH++X+2Pr7xWez/Omuur7/urx8p/q7aNrlvOP9bMd6u1gt1wq+wHf66+weUPjgjvkOWj7KEBw4M47VMvpvtXt37Dk+96W694Xa9B8flfrWxUzrc7+gyPZ12fE3+Tv1cfNGhQu4Pexlq7g/4htksuucRuvPFGW7t2rZ1yyin2Wf8/QQAAIABJREFU/PPPJ3//2c9+Zr/85S/N7P8/xb2tR9AxronK9ny9jED8x5CFARl9bvq7VhSFjVsa8z/Z/PgtRUdB8KetLBH852emeWsaBYICRyQ8y8s6lkURI2Ndh5eI/O+fj1FZoldvVFGmz98xNvztV1U0PJQeGfu2FUVhG3eUUbNPdRxtoxeVERqiQEURo8Bc91qFrk5ZESMeivoWRWH7Dx1J3i3LR9nqrWVETVHpWweXSO+Tk8po9eINO2uuo/9QnilGE98KNNA11e/3mZpGM257aWG4jkjdnQ1lxPLUTqPD334hpUyyvIww+CgGz/svj04Jc0UP3CyPkdaiKMI3J8qg0fwrXA3vtdvKKNl6ia4RsX9kXPmtdu47WDMuByoknAjnV++dGCL+PMsWyW3N8jTq+8ybZRT15hfm21eqSOHiDSVzZMaqNHf3xoqtURSRdXDbS2Uk/XPC1hg4I53b945aVjOWRH006sv9ya1ukLEkisn9dCyJxtCXvlc+/3aJYhKlvmdk+SwajaET7SGq9bPeM0LEbsRbG60oInOEftFDMeL44qwy2ndt39mBJbNy8247ePBgAIUQfVQ2wt0jlyXvluWj7MiRxhDl//GT00Pt406vLg7XEb2FEXKhPAs0Y+730pwYqWItE/XhWTTqxF4y990PrCgKW7ttb/jO7D2M5fKNJUPj7K7jE/ZPURQh4n3pY2+G6CRRs8krtiRjeU63CeEZie7/8cUFYQ+aUz1LX7fGf9prRriuexVR07Hcue+gNTY2hpx0IsM6ljA7HhhTRuC/cnd8FphQsDh0byAixt7wk6fiPs5e/dUq2jVqUTmHNJLVS6K+Bw8eDGDaqZ1GJ+ypoihsZhXxvuihSSG62338CiuKGPnju2V5ZHIR8b6u/5wQAZy4bFOy/onIXfzw5PD8GvUlD3npezsDI+Hr978e5vyv+0VGCGcN3+K02+PecGWvWGuc3y6Kwpa+tzPMgXqRZO7PN4CNcFCYN7An/jSo3BuUlcO4zF7zQXLWnHvPxLCXMZZEPBHYyvJRtmt/GSkdVu0NP+89I2GEFEVkHHEvnc+6ftnLlr6305Zt3BnWzpjFtefvzaSQSKR4z779JbBX7XuwZG4ZFPdE2B5EmL/5YLnPKivnD1U0/Zk343xmzjEvfvLU9JrzRNcxjMIsH2UvzloXor509o+iKJJIPGexslGa66SYYKtkeRmtL4oiuVeWR9trvzCFYGecL8wxfy3/TdfYyxWL4KqKHaLsI+bGG29vtqIoAqvoruHlfL5dWBnsc999dIr9pl9kHNw0cF6wO4has1Z/029O2Odg3rFHDVvwXlBnX75xV/K3hgXvJd9VWTmMQ5aX54uu1UGz14WzjrXVFnp7BL3ttXYH/UNs3/rWt+zaa6+1pqYm+1//63/ViMSdffbZIaqOSNycOTGfcvbs2f/Pi8QRjUA9l1ykWwYvDLUiyelE0AbRL5TTzVKRnYudQrbWTcfIpAVV8TXRQd9Z5cChkkz+tuZY8zdUfTWnk7wkOmXEtBSO5uXREIqjj1xc5lGqMBH5sdS0NbOExp/lMY9y8JwofEKOI4J7W/ceTq7R/hMReFGRp89IKTszq8l1/OvQ+EyMASI+Wq7lj04RHI0Bs6j+jv7A9yr13KIo7NL7Uwddy82Qn8r1WtZJc5+zvNQY0DH4dMfRiaKrmSXCR/SjVZ6fagl4ZW3NSeab0ci3vvmFBTWCewjm0MlxNItiSYimoXptFkUC6Q+OjXVkybkjL1+fBQEdDDKe3yzm3HE/HUvyWekIEqpYEkJsPIvOe/qx46Xw0BipU+3r/Pp8Zi3/94oIJ2r1haIoQgScruX/yOnm3bK83EMQ/rvo4clBW0FL1pEvizCiPouWKszyNJ+fZyM3mfJMZrF2MH1RpRKsZRxVVMssLQ2pmhlmUcTr292n1IgQaU4pc5em+cSa/2wWBcXoqs5MfrSOJdoC7EmsdR1LcnPvCakXUaeB9cS87D897g0YxuwNlBsziwrJ3Hd8NYd0XrJ3/mlwCSS+WIcls62qmbxAyjV5MUuUu7Ufr+bzy/Ni7jrzYkpVboz9mGf8dvdYLUNL66nWB1oYp3cZK/t5nEMoU1P1QvdZ1j/nJWKlPP/pXcaG/GfVFkD5HP0NxMU01xitGEoRmkXRQjp51CulPjj7LOXGGGcqkGR5zOfXvcELfKmQm5/PWvddhVPR3vhEh3j+6lmHKC1jmeWj7PCRRmtoaAjOO2CH7omI0pLTfFGlm4L2xm8HzAuVOHQ+o1WDUOaVvWdG0dGqqoYKw5GDnuXl8w90wqLkWptFIbOZa3aEMdeShc01xN4+2HckfP8te8o14ec8Tc88/Z7a6l03W2rRU/2BNa36DlR2QQvBlwPUCixo8lz6t6lBWJB56vUpEF38xTOzrF+1B/6hOnc5556bsS6pEGQWy/0OW/h+uEf/6SVwBJuC387yKLJHdYHnZqxL6tS3ldaWfIP2VrZ2B/3v1Dp27GhTp061devW2ZIlS6xTp072n/7Tf7IJE8rSR4899ph97GMfs6FDh9rq1autc+fO9l//63+1NWuiSM6ll15qX/ziF23WrFk2a9YsO/PMM/+fL7MG1Rb1XFWH9Ycy6rccHJ+WEiC3Skm2C5165zxn6KthRwmSCaKKvftg6aBjrGIQ3iICJjgxbMQIHZlZUk4qy6PTp8IhOBhXyrPoAZzl0WnSmuwoYlPCyiw6W3QMdkSeru4zOxjKfSpnWOt0+n5lr/hMquyLWvvmPeXvIwhDV9AAATiM23qq0XQ1WvjmiP8g6FcURaA50seIU4kwIKJnWiILoR06z69iaTwnqtEqIEjHCFf195+4g9Zfh8idmSWlibygH4J1dAWDEKnigFcwCICI/vC4CNYBcLE2LhankhxFuir8Mu+5n5bIUiV2fX410lC2fWT8O2FMPiVie2q0UCLrx09OT2r3mllS7ijL0/J/ABNXPTs7qb5QFEVN6oWW/0MVnXcD5ENM7Iw7x9WI3JnFusJ8C3WuMLboGJJmFqKQXKfP4h0aRIi27SuBo090GJWIapmlpSE/5QxonJaLHp5cI/DlATmtKa+lo7RknVl0+umqIE45OsYyy2PZSxwu9jStLgCIBvB0vpTPwyGhD5i5LvwNsSvAWAULmLM4GBOrOaSCnnz72yr2kVK26R/sKxXEVf3di1mq0+/nMwr8V/eZHdbY1FWlg65Ge5aXda9pWmYKh3rNB/uTmtxULlDAiX0SsOP0OuXGiNQC8uj8Gifrj/Yd0YrI8giYmcUSjIgt6j4L2E0H5EFY78w7x9WUG0Ms8QwBmRHVYm/40ZPTw5yhWobfLxXkAVT+y8uLEufqqNTMBizV8xdQ+R7R22hsLB10dEBYz7onAqxz7rPPjl1aggBXPDUjKf1G450503/+9MxEDM/MknWs+8yoxZvDO9C1ZJeK5nYT4d2WmlfSB0AA8PdznqZ2DUCgivb5a2kz1+wIe6l+a7N0jXGOYbv4iiuq6j5ZKlboWdV52NJQQQa7Su/J2sLGo+pN9wkrwzdHXPZaEZvT71oUhV1Ssfz4vU9IEEmFAv1Z1xZaW/IN2lvZ2h30v1O77rrrLMsy+8hHPmL/43/8D7vkkkuCc067//777X//7/9t//AP/2Dnn39+ouJuZrZz50676qqr7KMf/ah99KMftauuusp27979f/UcbWkRFkUR8ig5BLTmuC9hhWNEP61TjBYoSkwEAAQflV+6GnZEbDQSuedQWQIKFBqn8daXImpOmSyiGmd3jQ66lhbL8hh5KcRAwFn7+dPRQMCxoeM0vb25PPS+fPeERJmd9iNH4cYBVVQapLefOMPQm33XZ1J1VRyCrVWUabiLrnUS0IDvgQK5lsHxSvIDxWjhMEZJ9fIqslMURcgvj+MTDUeiGETZVDX6T4PTiD1RMo3sankkGsYoHSNclaF/JErNNAybLE8jrRoB84c+it90VbPFICFapmAQEQN69/HRQScKQPTmEnEq/ZzR52ducz8tfYPhQkdBXAEfIqqPTlgZrtN68mq0qKI0olpEgvYcTKmRWv5Pa0IDHL2/u6TGktNJ1/J/GHO8GyDfTpkLjHfXEVERn30ChWh1rjxDY3gVoTGLTBvGTZ/lfEnVyfJYalKfhfvxXTWy5OfzAinf5cuNeUBOnWKdl4hqARb4PVcVxKlFz1hmeXSumEM/q4xirS7AvwcU0/J5WqEjy2NNeR1nzgUFC1BIplPzWQEzHKg/v1wK1g0b1hAcejrsKa1p7RW4Vbnbz2etuEG5selVubHxjsml85k9MX9lcXDc1m4/YE1NTWEfQm1fK1SwtgFylF3jmVyAPOr8ABpoJNkzuSaKE8HehqOt+yxrhA7IQ8T+813G1pQbW1VF13WvRe37jRXl3nBZz2k1jBDPytH5zLy87aW3avZZHHZYMnrW8U4KIBdFUebDVzRqggO6JwLSch37LIDZhQ9NCvNa5zPPAnD0y2dnhW9G9QJdx5fIHH9t4cbAfKEzP83MLqpYhPPW7QyAo7JY6jVV0t99sDHYB+zxft+hKYgEqKpMDn8tDfDvu4++mTjW/jexJR4aVwJMvuLK02+uCd9bK/Uo26vriOXBNsCu0goG2DnYeAqY6Xo0S+up63ctisJ+WNkorFWtIw+bsPuElTVnXVtobck3aG9la3fQT7LWlhZhURR2auWgQ5vWCIQvN+aphZ+R0ma6aXua5p5DqaGvhh33oARPlsdyWtBaMTKV1sZhySF5TrcItgyZlypsEy1oamoKBiEHgj4LVC06kQsiEGfcOa4u/RZnlo4DrQgxyLwi+BzivuszKfWLvxNl8tHbLvJMOBawD9Sp1LHO8rRsDAceBhmRnaIo7KcPpw66OpUYlRx8HeuABf75dV7wnL3FyIGenOWpEf6ufI96By20yixPI63Mi1/3mxNoruuqQ98bnDrXmBfM1S/JXPPsEHWK+WaAHupUYvjR1QhnXnA/ZUbc49TceX417ogqwBwxS6NyarRouSPYLJPe2WZm5XrRMneXSvk/Shpd2WtmQsUsisI6PZM66H+QdAEcId6N8ojHjzeFvGkiL3eLU0n0FiNen+W3jqFBaoqZhXxjorDKjLjYRRwpNanGKfcjTaYes4P5TDTya/e+XkPnNIvR/CxPneKXZV5+pXpenkVZJowbjZrUv5KoN+WeiB4DnEFHNYvAEeNcr9wY/cXZG8LfiFxBMVWwgL2azhwys/Bdidj/deji4HjpGs/yyJ6Cln1OtwkJO4um4IrO5zEyL325samrUjBNy1kC6v7HkEVB62PDjvJMBDTBuaUGt1kEH0krqVdujA7Io2uVvVgjycx1OmCHWQR1uW+HV+M+68EVQB7Ax8/cPiYpS2Vmtn7HgZr5zBzSWuW+LJVn5eh8Zl7+cdDC4FyxTxHl50z4xTPxrANEYyw/2SE66OQ90xWYwD7gevZZovxn3DkuKZdGg2XC/n51n9nRiau+Fet45OJNYS/J8pJV6GvC3zs6RshjDfBdIRVF2Q71mgYQ9hwqArhIGpP/TgDWCqSSnvOJDmn9dP6urEd1kEkxBNzQ38Tm4RzSsodmKesyAL5PRNYF35TqP9hV89eXZ+cFD02KTn517lJO7/cvzE9SqMzi/jVg5rrkuxZFEUQQWaundorvC0B47+i3w76o+9SH3dqSb9DeytbuoJ9krS0twqIognrupoqWTW7Ylb1n1hzK3lj8XOdI53tEHNfzHU1ToxDesNO63PydHDgoUTgOSmsjvxDDSnPgtP56lqe1fIm8cGjqs+gzZHmkP5F3+pnbx4T8OKXfYvzTt+0rHXRFpesh+J6aW298OPzU+CLKBFpN12cimsB16lRC/aOrEQ6QgJFIjn5RFEG9ma5OJYcvVPfOwyJYoHWas7yk75ml1Dyekxx9Mws09CxPjXCMys93GVvjVJpFuq0aa2ZpyoGvu+xz3nWu8c1xqr98dxxLnDK65hliRAN2qFPpQR01wgGfuJ+CHRhLdJwIpUfy2wBTZqnRr0YLTsu/PPZmTc6umQWHkXlMg5p7xVMzAui1bV/poKvaeZaXhjoN+ivvppEeovzsO2rw8t9w1vRZbnEMDc3nZy/iW2iaDEYaHT0CjZJzPwU7oPT7+bxiSxn1PafbhBo6p1kKyH3jwejQKCjqtRGUFpzlpRNPw4glpzzLo7YAeaPogdwnY0m6DWtdtRE6OobG4Dlxb2Be8W4KFuAk0XUOsecSse/w6pLgeCmYluWRPaW0bL5vH9HK0G+n81lB0W8JzdgsOgR0rcENYPvHQQvD9wW0Zl3AHFB9ChzeP1cOwVldm0+1UvAO/QLOHI0k+1Qr3dsYL0A4ZU35b7d8U2ljkF7xqY6jAygD2IFDp505RIT1O49OqWGEmKWsHJ3PUL/VuWKfIspPFFTPOgCcP4tzxTxR4TjmEI35j1MGM0JBV0CsQTKfSZPD4bym75ya/Gpdx8raGDhzXZgzdNUDQOxx4YZdwZFXoLJe03SQfYeLAAjA7DnbpeTAltH31P8N0KK/q0w6BWBYG4B1+jt8T1I7fNrPUNEjIVXxR09OD2PHPsqehN2gWjLYcZy7MLSu7D2zhuqv6YLMo8FzSuG5m6rKFqzV0ySIpOxH1vSbsk992K0t+QbtrWztDvpJ1trSIiyKIpT1II9ygojWcPBxKB9wuX+a16wosadpmlmCPl8jhh0GgzoeHDwgsBiZSmtjs4cyqzmdb72XqlZrVJYIBLQzfRaf001UVnMG7x9TGgpKv+W/0bdXBrui0vUQfB/5U2OCRoTlOjHaiDJNd/mp+kw4xRh76lR68S80BswsRLKhoxHZKYoilM+iq1OJ4YVRrGABY+2fX51i3k+NcOYRxhpNhbrqOZVKt1UaK3TSXz47q0ZwT9kVWZ4K7jE3GRMFg3yedg9x5DA0cY7Vqfx3J9Q3WYxwqLncT9MpyDum8/xmFiJaOLMKTN0sDAxlvjBHv/PolJqcXbM0V/4HPWLKD+JWl0vkdPv+Ukn7PleyTtMF0FTg3TRnlyg/II/mbLIX4FTqsyAiSdd8ftJtcGg0TcZTgldVkSo1aLkfaTJmkTZP31UBZkTszrxznGgjxGdRQE6dYqVlq0AZTXPlr39ubvjvpOnoexA1w6Fi34WOamYh7QWHW3UaEB+ja14tIBp7r4IFGi3zcwi2CmBHp9eig44jQ993uHTQFYSrlx6kufJqhCst24uVeqE+9DXM0ogdKRuA1qwnwEBlYcCwAERQIBSHgK7gHXnuUHk1kqxrNctTJ4I9kW+nrKlHHHi3YktpY6huAs8JELpjfwq66xxCROziRybXZYSwT2V5GQWlcWbdMGBejXPl55Cev5xZPCOK+A0NDaECAF2BCeYCIBzMiHraG3rWAeQSef91vznJN3t26rvJOtbfeXbquzWA/rWyHpRFSArLdf3Ltbvmg/1248B5dnWf2Xb9c/OCnaTn4YEjR8NvsP9f7Bh37Dv6fVWLBMFIUg6yPE0FVPYUIqloCehvwpa6okrDQP+gewU4KZtKgVvWS5aXADwsG+wGUh+/cMe4RAzXLIJDl3SfUnNWs3/1nrIm2A1D5pZq7JRrA8BTALiX6Plwrk1btd3aSmtLvkF7K1u7g36Stba0CIuiCPUxyaOcIqgqjgWH8jFH71Q0VlFiT9M0Sw19PchA/buJYdh4tER+MVRA6tVpAp3FOT5PcuBw4OhKjeS3uJ8amT4izUGidC+uU8roy45ST4RbUWlFemnesaf/pn80wtEE0DzbvZUR6x1tfSaiN1x3rjiVa5xTqUY4Rg6OF3oBRVGEmsp0jexgwJH7qmCBdyqJkimlj+dUwTqcK4w12qaKsnlapzF1D9ofSg6n0lhVEwBGB3oBZpYIJWmE5m8TS+MQGr8KIm1z4l8atSZiiGOmDoFnXagRDujA/TSdYqATJsKJMItROaKZT78ZHXSMqixPmS9qhGNwz1gdx1Kp+JfL80+qjDtVUN91oCxn88iAVPzrNnGKiTrxbrqHMIfYPx4QRXwcEkCty0X1mggYXUW1iFqz/jTK5QXRVm8rcz11n+N+qo2gDI0sH2V7DqZO5eldxtbQOf031/dWA9fn7JqlVPzfikDZoMrwZ75rGgjPTTRYqwvgVLLmVBvBO3lD50dFfPbj71Xly66TfUqF6rI85n2bRYCBf9OlYWlwvChHRcepUFp2PYEvpeKrEa7nlxcr9VooOp9xKn87YF6N1gcOo1ZXoHF+8YwKhHotFAXv+C3OE40k/9lpoejextzj2ykQ6nOioUbr+QXgROWOfYfT9LMsj3NIKciAQFq5Q1k5FwnIM2Tue2F+fMZVOmC8eA+1BTizGMvPdo4Oev/pabRaGVo4abybMiM0yp/l6VkHDZ3I+3X95yYg/Sc7REdv/LItIcLPfsD3ZX7r/q5ij6pWblZ77mPXKHPnUOOx4JADYv7QaRMwphpAOH68KVGCN7MEBNO1ovni6LqQoqG/qRU2zGIqAmk//M4PekwLQMZPe81Izqpr+s6poZVv2ROruBDgIXUBNtKXuk2oAczYv3q+sSpEyl+eVzrod1bsLdaXAsAKwgHiz1jT7qC3t+Zbu4N+krW2tAi1PmaI+gqtDSdYD2WleWleM9GcGwbMC4ciNE0zS2iY6oBCl1J6HuW0yAejay6uGigc+DQf6VfaNJRXDhk1Mhe5yDsHiaLSXKeU0aPHjgfnKMtjhFhR6d8I0ks71HjMxi7dHA5AukbJcP5/LrXLMWL98+ozYQTgrKlTuftgmm+tRjjoNFHMq56dHebK9T1SB12dSvJSORgVLABkoBMl03xe3k8F61SVWJ1KpWwSdVWnUimiGmnVskHeCDeLwlp8ZxrloXBMVBDJi3+pI8dcIZKgpZS8kr4a4fx7nF81wgEZ6DBfzKKAFAJ0Ou9hmmR5ynxRI/wSl7NrZon2gT4/9EgVTtpzqKzn2uOF1EFXpxhNBcZSc3YxsOmIEpnFyBtU1R+J6rWWZcryVJkXQ4zrNA/U5+y+K04xRi7XqQDUJU4QDcAM4OjUTqNr6JxmaW57lkdHSJX0vSCSWSxvluVpmTg0FRhLTQPBiKVrdQHmJfu7qvMTyaJryTocVdaclhvzgmhq+JLriyN15/BlwfG6rGeaZoAKvZZgrJcepICuzmcVvvJipV5JX+fzECnPpikbZhEAYs9QwAmnDQBI2TVe5VvBO/YavoVGkhVM83sboAMOs6rze9FQKjzUU+QGCFW2SJanpVM5X/75/jdCJFkrd2ik/+JmSjD6yiMAQJyXev5S6o6xPL3L2DBPhsxJdVOUOQA7jXdTR9kr4r8iZx3nC6D09c/Ns6PHjgcWRpbH82zi8q125OixAJY9OmFlWCvsB2qDKIuQ9c18gykAeIZwpX6nw8WxUDUHcNoLiwIo6loxi1R4ABoPKFINJbCgnpieMCmKY8eTM9Y7774k6iwp1xbAxt4z7djxprA+ruw1s4ZWrlF6QHCAcQUIWI+c1Wg7PDphZaKTVBSFPTxgeLJWFQgdJGVv+faz3o1n3Yfd2pJv0N7K1u6gn2StLS3CxsboqBH1JSp70cOTg2Goh7LSLZUupQZOPZqmUnrVASXnC8dQDxBPEdRcXCJq0Fu//kA8HL3Kr9KmMXAizTMamT7yDm1aI2pcp5RRs9QgJkKMAvOXuk1ISoP4Vrg8Uy3jQ36q0mMxYlGXp2vEEVo5kTw1Hjz1D40Bs6hkj2NDZKfM70qpy+pUXiMCalme0pO1hF6WR40Bs+gI8X4qWHepRGfVCFcthHoHrUagNEqm+an8nSiDWRqhUAMQBgDGno6lWarGr7RyjBMi01pKyUdR1KHhOfgGykaAkk7HiTCLDAAiFUoJ1miGlolbKMrjF7ucXX0H//w4QlpicN/h0kHvPSh10NUp5jkYS83Z9YCcOpU4A0T0rxDVawAUugoGwrBQkTmaF0RbJ04xDAvup2wEpW5meRS1xKjM8lE1dE6aXkfDIbi857QaQSQzC2XNsjwVKMMRYiw1DQQVY7pWFwAcgsWgaSD9XBRWc47Z+2Al6D7lBdEU5AEUBcTrOmJ5cLx+1jvV4SC9SY13HC/VyiDiluWpEa61nXFM3mpGrFTnM/usAsloC/j5pYATzhaOgqZaebFSBe9w6gA2NJJ8n8td172NPYFvp0KKPuUJFoZSp3lO2AiqXZHlKcijoof1GCEKJCgLQ1OJPu2AUD+/9PwllYhn/MId48I8Gb4wHUsFLYm4c52yaxTYzvL0rGNfBhhU8AsWD8/POgaseWDsijAHuYeCyFy/fNPeRIzNLK4/0k8IWCiA13j0eFJN4tjxphp1fzR+lFFmFoEH1qCvVsH5q8DgMYm8b9t3OGgTnNZpTPIcxbHjgRlG2o+WoSV3HE2FSUKj92w3XY+ArADj3ibiuXT8Hhq3ItFJKorCermzRwFg9sur+8wOexjpL22htSXfoL2Vrd1BP8laW1qEh4/EjZeorxrs9Q5l3exVOV1pXFpHlqYRQ6Vpgqhr9IzmIxCai6s5pVmeKhH751RHBWO23qHsSyhpHiUOLddpdM8sVYAnQqw5VhwkGpGi+fxnLePDuKpTQBkcT1XXZyK3EWdNRXzMYlQry1MjnMMXIAPDsSgK+8OTqYNeL2qNk6iU2vnrdyXXYYSbWTCAeD8V8VGDRI1wNRhwEPWgVQNXo2SIB+pYAkyZWZLnrwYguYYc6n6uXShOquodYLxzHYJ7ZhZq79LVCAes4DplI/iyWzBfzGJeK3NcKcGIP2Z5ynyB5XHefa8npYHqPaeWgiJqouvsYONRK4rC+g1JjSR1iqESc69zWsjZVaeS6C2RvCt7RVGtPk5NedKKmHrB/GdMNXXBi2ohZGUWheC4n7IRrnSCaABmKqyEMTrZqQTrdTSlZWtN+XrPqQJl7A2MpWoLeAErFSijEgArOBnBAAAgAElEQVQAmKaBeLaLlqyDoo/jq/uUF0RTkIdoMVHfe0ZFB/3avmmJPNKblOWD46X5w/qcaoQrI4S5uXhj6aB7o1/nM46FshU4E1+cnY6JAk68NwCQplp5tovuDUQTOU80kqxslywfZXPWxvXIN2N+qZCiB2wBnPS9AZyUjUCUO8tTkAea8ZfvnhD2YmWn6HOqGKemEn3SsRF8LXoFeYiiMpZn3Bkd9InL0rFU5gDgP++m7Bqfz69nHd+AiP3vno/zWVPydB1zzncbuTxUpNDgA3sBLMIVW/bWCLABbEBhx5nVOX/02PGEubf/yNGaSgnMi427ooitWdTWoJoFLAA6wBNVYFgHgOtvb96bpJhohY1tew+HfQBGCKX6zu46vobOP0tSqDzbTe0t9iRNXTjLieJx1mkddkC/hrfet6Io7Pmh6dmjADBr/Ge9Z4Y9af76XdZWWlvyDdpb2dod9JOstaVFePBwjFIQ9VXU/Id1DmXNh/zy3TFaAH34J0/NqEvT1Nrbatjx33HwlGLnDRyNakJLQwVeRZfMUpXf52asq/nv3E8PZbO0hrbmUfLfceIeEefBLM2zBqF+X5BtDpJhC9+3ek0j/lqrGcdKDQbUWX3EXx0aHCuiBBe48dHfUyPc5wiC7hdFYX96KnXQNUqGkQN1Ucdnncv9BGDQ9+Z51AhX8Ss1wjWnEiOcPFOzKESW5WmUDFEcfXeMcLPIHsjyNGqNA8iY+Ln2Y4nIq94BQAHXaSklFe5RY8ssOoBcp6kLvpKCAgwoPOOwKRthlqRRKPNl2aZyvZ97z8S6RgupK/75KS+nQM/h4pgVRWEvOCNJnWIcK95N9xCfX69OJdFbLb1I8w6UCgbiWADKtKR6rYJ7CJtxv77CwvmVy10HcFKKKsa3VwlWtgVtutCyT3M5u2ZpXrgKlGFwMpYawaNiAV1V6Imus5drzq53oLRkHePFN9dofncHrihgxn0Yy/tGvx0cr98/nwploiCuY4njpfnDyspRI/wtoWXjmKhYqZYNVJAHZ0WdIM7Eca5+ugJOjCUAkLJrfDUR3Rs4WzlPNJLsxccUMOP5gjq/MJW8Hka9Cg8ATipWylzP8lTrA2rzWV3Hh/sqO0XXq7IwGEtlfeFc+Si/nr9EpLnui3eND/Nk+qp0LLsJcwChWd5N2TU+XUDPOt4J9peeu74MJuuYKH/nYUsDoNDxtSUB5GAP0RJpqlZuVpv6RMRfgefjx5sS4P6DfUdqqk4AGmAHkG9NSggArQr0ZnkE/7QkoVlkdUxfvT38JnvKOeK8w1CDLaYAwbCF5f4B827xxhhd5/cBozU9DKaWAuO+DCZnHWvurhHLApgzfNEmK4rCXhvWkAQ7VLRxnDDoVGW/rbS25Bu0t7K1O+gnWWtLi3D/oWjsE/VNUPM6h7IeEufWKW12WTM0Ta29rYYdzhQHotbpnLkmzc2uV9pMld61qRGtec04U9xPD2WzNF9LacdEJ7muuzgPZmlEB4NdnSkOEkXwtanhrkY4oit6WJEC4A0yRFvMorGDIefHRw0Q1RiAZsyhjuGoCql0jZJhFHA4qnPlhYjQGDCzUO6M99MUAEANjMR6vweVUA9aFfrRKBklxXQsyR82S2nnGrVGfIkx8WOpavwaaSWnEocGwT2zKFhDV4CBuVJPgduX3UKgzCzSKpnDykYgysHaphGRP6fbhLpGC0ZclqeloBZUTBvWRZaX0c+iKOzlV1MHXZ1iNBV4N91DNMqf5anqNSkkSlmnYRTSlfmC0c51GqG5zVHcVXCP9+I6FS8EFNT3NkupxHwDrxKsKQE0pWXXEy9UWrAq4vNtGEtNAwGMoqsKPc40z6g5uz4dRdObcHYYG43me0E0nc+MIWDhA2NXBMfrtpfSagYoiOtY8g01f1hZOWqEK8Dsy1SZpfusgjycX6pMTurCPCfGqVoogCc4e5pq5dNR6rEw2Ic1kuyBqgWyHhUIyPKUqeQZAsrCgAHGc+reoFUJVEQMBtgZd4yrWzd6tOwNysKoV+EB58pH+fX8ZQ7xjGd3jQ76gnXpWOr+DLDKdcpU8mwEBZxIdWK/1XP3Dy7yzjom3eGvQxcHxk/nYUsDGARbg+jv6m37A0D9hTvSHG6o8WhAaFoH7XQpU6eCnLo2/e8DAHAGe6E8ctPZb1kHzMnhizbZhh0Hkz2F6Pf01dsTFXWztBIAZy+aCgryYIsARitwBHNPmRHKZsnyCKZ3l3FHY2fk4k1hrmg5Oj3rJknZW8+uaQutLfkG7a1s7Q76Sdba0iLcdzA6eAiPaf3ZeoeyRjVVeEzrKfvSKmZp7W017DA+cZwVwV+5NaXz6uZNziOH3LdEpMYsNb41ksi/5356KJtZEkFR2jHOD9ep82CWRlmIEGuOFdepgaBND1FVCcZgVkVzmhd70ygZxg5Ol+YImqUGiBrhpCJwyJECUBSF5U+nDrpGybzAlz6Lz3MEYDCLBjPvpykAKvamRrhS/zCE9KBVNX6NkmEw61gy783SqLZGrQdWUWTGxI8lxkWWp5FWoi0ocyO4p9+HrhF00iG4n0+nAADL8hRgQDmYuaqChGpE6ViqAYXRr2OpAoZaCorIyOnyLMeON1lRFDZsWOqgq1NMri/vppRgD8ip6jXRW8AVHUsf4VTmCwYc1ynI50XiVHCP9ch1CvJ5xx7ASbUqAGW8SrCmbdCgwF740KSESkrTqLYKlPHejKVqC5C6QFeBMlhLzBNNA/ERzrFLY3oT+bd8c61v7wEndSo5R2B2PDzunWBM3/5aKmZHU2eTSKOyj5SVo0Z4BJgnhm9AuTGzNJqoIA9pBpquAl3Zl1JULRSiqIAQylTy5T51b2CNcy5oJNmX+ySH3izOZ95NdRrMLAHM3q9T4YHn1L1BKdCqeq1R1EvrlLNUVo6yMCbVYSoBJHpQWWuDk5bBded0mxDmydvvp2lSuj+jQ8N1Crz4CiKj5azDlgH00HP3Di/UV61j2A23vvRW2N/vaFganGfSazjX3v1gfyK41tTUFM4LdHQAddCwUBYhkesVW/aG92OP4KxkfrL+NcpvVlsWclE1n0ZIeUezmDbYf/rasL5ILcNuanjr/ZBWCCNEz2PSEkmN0+g6a0sZIZ8W4cUsT5kRqr2R5ZHRwv7V4dXF4RuOXrI5zBUVl1XRRnRTvt19St1SwB92a0u+QXsrW7uDfpK1trQIRy2KhgDGCMjp6V3G1q0xraWJVM06lGt6eHJdmuactTEKoU4xkXUMAEXwFVH2mzf5vVAFVYnYLK3nq+JCPD/300PZLK3nq04TzgvXqfPg3w8KukaBuE4NBG2ay6tGOAJSGFF6ePuceTXCcTY5iPz4qAGiGgOMK2kKGI5FUdjtz6YOukbJ/ujqeuuzmEXRrSwflfx3HGzeT41wdaDUCFflYZxVPWhV3V6NNeaoGqTMe7MoIpPlqeAeFGqooH4sHxRBLo20YrwDWGkpJZ9vPV6+gYokZXltOoWyPBRg4L9jpKs6vzqPKgSlUbJ6lGAc+CxPnWIilUoZbmpqCkbS5zrHlA0tE4ezybspJdgDcjqHiN4COOlYoihPV6cY0S+uU5DPU9XVQWfdcJ2CfJ0cNV4BJ4xnDHSvEqz3pCktm7+peCEiU1meCpQR9WUsVVuA9Bq6ihfitAAcaRqI14vQeUnuJ99co/leEE2dSvZoAKTu46ODfvfIZeEa3dsU1MMxUfbRXseioSngdI7QjGnqgP/y2eigA96dJ/swTChNqcnyVAslMJUqp0DLjXm9CN0bcM40F53mmSSIgZlFVhHzyzO5tFa2sjAAVb5Vh6mk1SuIwppZEAo7tdPo8A2UnaKsHGVhANZ/qw5TyUf59fyFqcRYfuWeiWGerPsgjbwrqwiwnvsp8OId9LFLa8vEAQDdKuducxohPOPNLywIQqx3Dl9WU/aONblu+4Fkrh45eixE/NHV4N95NXYzS1hNfAPO5it7z7Rt+w4nc94/o1ltLjdpZCrmp+PYffw7wekntQwA/pbBC8NzI76r1VhQtic1Tmn77G8K3gUl+ypgoMwImAZ0WJ580/8Yskjq1G8Jc0Uj7yraCBPmgocmJSJ+baW1Jd+gvZWt3UE/yVpbWoQYoWqMnKjGtIqu1FOD/uf73wjOmBq8WoP2tiHxIITy6mt+mtXWXdfNGzoyz6g5cGZpuSCtPU6uNPdTZ9jMEjV5RXr590SBvAOq+eDkUerBxfUakdKmpZuoBWoWIzsYmyric8ypsWuOI3XpQc/9+KgysYpqYYSTGw7boSgK69YvddD1oPVRRXUIzFLDWBuRSt5PcwTVgFEjXGnegEF60Oq3UFo2kcpzJKKg+fDq6ClFn7q+GoXSpoJcKsyG8c43UqVmT2NVlgp5qdzPG+GqQq+Ce9CnMcZVsdgsCpSpEa75i/UowcrS0OcnUkmnBjdGkkYqVWka54N3U/FCNeYw9mhEb9mz9FnYe+qtWwA5nkefxSuPK8UdY5L7KSWYNUKHlm0WI5X8XwX5zFIwhwbYofvxDhH/U0dP8/mhsXMvZUYcLo4luZhKr2a+ssaVErzKgSQqcueV4XXv9HohysLAYGYvemziyjBP/jYh5teryJ1ZpGWzdyr7qKmpKZwzaoQr4HR2oBlHB10rQyjIQ/USjTYCtHoGkGqhwISBlaPlxjY5kET3BqKVvJuC1h5wUgYAADLfXNOazGJKR5anJSQBY3DGNV3g23L26Jmupa7qlbNUVo4qp8OEUcd/vwCJygBSpximEmP51Xujg759b6q3otR+WF/cT4EXGDt0BaNxqrEhFPxS7Y0sj2yxWKprXlgPXUcsT86/bfsOJ9R0Pa92HWgMyv1eA+N9p8au32bG6u1JFRGuubL3zABssv6Hixiafnsd96amppp8cajjnV5bUuP0q8gvLEMV3wWEBrSgUo8GKQAKFLwDbMAuU2YEv0UHjGb/umXwwsBAGb8sOug3DojMO2Vowfo6777Xgw2gpYA/7NaWfIP2VrZ2B/0ka21pEf6L1Aglj1LzpusdygucMUxTIRQMK6VpNjU12f1jVtj1z80NFCuzeJgQQVa1brO0PJtu3hwmOMyXSg6cWZoTrnQ+AAbup4eyWWp8q1gWhzgRFu+AmpXUK3WSzSKFi/tpRErb6CWb7Zq+c+z65+YlEUyiZ0RMvBHbd9pau7rPbLv5xQWJgwHVjAPwe4+n4/P+7kN28wsL7C8vL0qiyAAfRAKhsRZFYUNcbrEetFraLMvTslRmJRPgV33nJFEks0g55f00H14FftQIV4MZJ0QPWmUWKH0XR07zUDUfvvFoWULmd8/PT/QToJwyJv/q5poagaqO3NvR2FWp+cjRY9bh1SV28wsL7M7hy5IoLDnt3M+nU0xbtd2u7Tcnqc1tFkV1mHNe7+CV+Rvtmr5zkv8ejMLbx9SlBJuVQMOv+81JRAE1ss49zaKDPmTOeru6z2y7YcC8pNwiqS68mxcvVAq4vh/rEqfrNzKWx443WedhS+3qPrOtw6tLgmNlFtMkuE5Vr3cdaLS/vLzIbho4vwYEwdjnOhUv1BJfn+iQAk5qBJd7SOqgH2o8Zn8dujgBZMjL1dxJFS9samqyu0cut+ufm5eAJ0QqGUtlmZiVhuzVfWbbH15ckERToaOzdlT8r6mpybqNXG5X95lt/2foogQAUrE6v3dqlD/LUxYGedZEFXu8viqJjN78wgK7us/sxIE1i2AHDskYxz4C0FAjXGnZOCZaTYSoaZantcfZG/T76ZpUAUlNk8BZgH3i01+IgPq9AZFTzgWNJB85Ws6Rq/vMbnZvoD/umFw3yN+1BCPAA8+p4N33Ho+ghbIwFDADSNA9QEtzqXI6YMd5rsIDTSue6BzC+eUZz7vv9TBPiqJI9AGU2g9bjusUeDl67Hiit6KCt6pfk+WpOr/XtWAdvyI51rzHPaOWB5CNf+urMTD33/1gf3DmfeUDBDv1jFcdIED8Z6e+KyKbE5K0DrOYpvLtai5iA2jQYu/hIghJsg6Uvu+dfgXuWCMqvstaY5+mUo8veZvlKXjHvARIVWZEX1edAzuF/evmFxYEds7E5VvDXOnwSlyrytBSvZV64N2H3dqSb9DeytbuoJ9krS0twp9LDVqivhoxu6jOoWxWv1TQ6m37wwHP35Sm2VxD8ZUNU9W6zdLIu27eGMkcyt4BVbEjpfNxOHI/PZTN0txgFctS4ZosT0vmtNRA0rlu4vKtJ75IGtEIDnxVam6pEQHgcPxBj2knvsgs1COlQ2Pl8HtMIl5KvdQ8bIyI1jQMVN5PjXAV+NF0CjNLooNZPipxAs3iHFXFdfJyPyv0azV+m2veWNN8S7PIcsjyVB3Zl7pSpeaWmhch8+kUzTWNhGV583oH2pRW+aU6lODmms/LJeqjBnW95kXILnKCe7AcsjwFeYhWfSFEXOZaaxoOC0alql631AA7uJ8qiONIZHmaLmBWSydd0AqVYMAOVdMm37Kl5kXIlGXSUlPBzixPWSYtNS+4pXsnAC1dgQSMbyLeT0xafcJ5Yhb3Tuionn0EPVyNcK3fXK+aiDLAlIWBg6WpOMqMUFaOpklAJyYi59NfVKxP9wZETllztzomV3ONyDvdM7nIx87ytAQjY8hzKkinjByt8KDUbIAGzwjh+VU5HRBfmUoK9Gg5Qk2TgE3Hdf98/xvJPNG9QyuW4CifI86eNk33oJ65WWTT8W7KXPO6FqxjrfONg03gAGdx/LItNWl+AH7z1u0MzDBSoOicI3rGozkwYtGmsCfNWbsz5PJ/quPoMHcR3ATwo4Slivbyv9dtPxDGm3UAg+HGgfNqnH6zyDigqy4HTDhAdS1f6+uwK3gHQE+OuzIjfEUJ2G7sXzcMmBcAjDdWRAf9obER+FCGlrJr6oF3H3ZrS75Beytbu4N+krW2tAhvEhEOjBEtbwNK6w9lpVXTMGDU+dESUM01BL2gSKmBYJYKrWkOOjnWGMTeAdVIv9L5cCS5nx7KZmkupUb6oQ7yfq11QHk+7qd08tY0ctuJkn3BMQyaa4MrJwJHVimILbXuLkpGOgKH34AZ0enUg9bT9fq5SHlzDeOI91MK4kChGaoRbpaWS6p30PLfNSJEhOKT4ty3psHyoF/eM51rGj1RKnT/6WkEQI2Wlpqv3euN8Oaar93rI471mjJmVHn4RA2tCjraESdyvNBUoHtxRwXkdI0RvcXwVdXrlhoODWWQ1ABsqcEe4jrdQ9R4VzqqmSVl57I8ZZk013hnrUetlODmmgr4ZXkq2tlSI2WDrpTglpqmxWR5Wm5sqxP/entzPN+uE7HHLC/ZR61x0GG6APpOcOAmDoMa4UrLrldNRFk5ysLw+eKfdMwIZeWoijt7FGCAT39RsT5NtSK9gnPBM7maa17rQ9NAzFJa8C45f4lmM6aaSoQTmOXRqfPvjCOl6SNmERRUMU6oxMpU0lQiTf36tYAkMJEYy68/kDroytLQFCRAZe6nwItZCggoQI7GCe+m6SM+zQBbgLX/4yenh8g9gQPm+eA5G2qqMeC8j1u2JbACPYBLdF6rMfy6ivIPmfdeCJjMW7czyeWHScP6x3n/ZIcSgFbRXtIH5q/fFfYBmF2qwA7gplU2/jQ4nXuqy0GghGobKnroy8NpOho2JiCRMiM8KwdmFM/9635zgn7ApHe2hbnSd2oMsihDS9liqhHQVlpb8g3aW9naHfSTrLWlRZgLFYimOUOgov5QVsVxmjfQsjylaTbXvGqwGghmKZ1Zc9ehOeEwe6dp/Y5o6CudDwMNx1UPZbO0dq1GiH1d1D7TWueAQsPkfprT2ZrmRZs8w6C55kWbVAiqpdZclIzDb+Rbkc6tB62vN+vpqs01zU33BpSW8VEj3CzSX+n+oNW/0bwR7qOfzTV9jixPafNmMWqHcUbzeYxaXrCldoszhOqlU9RrSlXFGDxRU+P1DKFhnqihzkvHqDyR4zXFGb7fdpRgBeQUmPDz8qaBrRvLf3cOjVe9bq5d6koa6R6iUX6fcnKeixbpHtJc0+gsXSnBzTV9jiyvZZk013xerlKCW2q+8oA6qlrTOMvTlBOvlv/0m61z0InOEknX6KdZXCdqhCstG/aQVhPRqKWyMNY4RohqfdDqzT3YFNzLp1pp9FbTJBDj5FzwTK7mGvnLdJ/morRgLcGIY8Z5qewajYxqxFTFOAHvNO3LLDr3KsaJc6dgvaad6FjqXgoQylh+88FJyTzRs1DTfhDc5H4KvJilNo2mUAGE8m5aDtKX1mMdo1D//R5TwzcE9CMN4olJq0MQAx0AnPdBczaE+3oAl5QoTfNDnO25GeuCxgjfgCgwVHVAbHXedx5oDOO5cdfBkEI0ftmWAOLD7OKc+2mvGUm5QhrvS1fxXYB2FN5V9PAaJ8apKVS8E2wYTTXyrBxYnuxfV/eZHc68KSs/CHNl2IJo+yhDS8HoepWGPuzWlnyD9la2dgf9JGttaRE+MCZuuDQVZsNg94eyCprRdjmBpyxvHU1zrjsI1UCg8Tc9eJVm6g96s7RWttL5VN3dH8pmqeCURohV3T3LWx8h1pJeWT7K3hRF/Na0Ra5Uz1mOYdBc49Cmaz3wllqP1+tHyTj8ZqyKlE09aFVEJstTdL2lpkq/WZ4a4VrGx+cqc8DSN+xID1r9G400DHo9I7xe83RHD3aoIatR38Fujmp5wZaaChViuLWmad3hLG9dOoU6xBhyrYkqbNmTAnIYlSdyvDwg991H04ijAnIqCumjt60FO2514oVKjW2pEZmpt4dolN+nnKgwlt9DmmteTCzLU0pwc82L43mWSXNthGOEeEpwc81H/Dq6vVMjpppy4mtKPzv13VY56NCyYctMcuAmwoFqhOt8himzcVfcG5SV81thYXiQ5DQHvJjFPUVz9gFCcbR9qpU6h1pmDa0Pv8+eqPlUIq95orRgLcFI9JUx0WoiKMpneRoxVVsANoJnhMBQUeV08peVqXTMpRLV29dxEBnLCx9KHXStoa5pP5xZ3M+nv+ieomU8AXh4NxX/U1aUrmNKdX3n0SnhzAP0g2rfdcTy8A7oAJDS8MSk1SGFyQuFYpsoCA8g89TkNcGWIPWOb0ruOOXazGK5vVVb9wVmzqbdh4Imx+A5G0J1EthIsBm/32NqYH4o6KfaG/yGn18ACip66AVkdW/AluT/quihD/rA8tQ0A60uwFx58514Xqtoo+4NACi6N3zYrS35Bu2tbO0O+knW2tIifHpK3HC1cdARpfSHspaxoB0Qajy9NTRN74CqGBiNv6kQzSuuVqx3mpqamsLBpHS+B50SsR7KZil1VyPEviZnayPE3gHVGs2tad5Q8AyD5prP31KjsqXmD2EYBhx+KzbF76W5yh74UKp3S+07j6Z508owUGEan6us+br1Dlr9G00dqyyvjX421ya6vGlVvfb305rlLzsWg9aNbqn9xQnutTadQnNJs7x16RS6bln3rYkqQCWmk0pwIsfL1zr3EUezOJZ/lqiij97+oZVghx9Lr3rdXPNjOUL2EDX0Pu1YGBe79d6aMj5+LLM8ina21Hyt828+OOmE15hFoT76r/u1zkHv5yJ+Wm7MLGXDaJqEB0n6TlvbKgfdsxE8uAloo0a4Lz2Z5Wm5MWXDaMqJsmCyvL7WB3/TPHPPRrisZ63WB39TcKi7K7PomVzNNV95wO8N0J2zPD1/L3H6FJrPr3ntPk0CR5OzVAW+9Hk0TcKzEbI8zefXMdEUpPEOCL344cnJPFkn+3fPN6KDruJnWV4//YW/adQX55d3U/E/r7FBygaR9QsfmhRKlfJdcZSVAUU1BgCZu0YsC7aEZ1hxnab5dR5W3WPCykAHh25P/XaE2XT9I3w3690dwRndsudwEHN9YtLqcH8YIQDiFz8yOdhlCvr5oIiK73KOA/ao6KG3DXRvwMEG2FTRQ8/KobF/XfHUjCAcOH319jBXlr4Xgz4q2qhgWb294cNubck3aG9la3fQT7LWlhbhkDnrazY/s1r6sD+UVUmW5uubZnnraJqKimd5qshL428q+OWjQPWcJvKi1Lj2VFk9lM3SHHzNo/RU2YGtjBB7qqzWaG5N8+PTWiEoX/aotUJQ3hHCCOfw27YnGkkqBHWfU6TVw7ul5sdH6+xqGR/vfJx5Z+qgq4K9WerA03yUrLWCe5NE6CnL64Md/E2jit54b60QlAo9ZXnr0ykUOMvykvZ3olbPaGlNVMGXREPt90SOl2fM+IijWRxLjYT56G1rwQ4/ll71urnmx1Kpsb7sljZVms7y1pXx8WOZ5Wl1geYamgr19seWmgecruvfOsE9H/G7w4GbPxZQQzUhPEjSf3rrHHRVQM/ytNynmYUIoBrhymaha7kxZeUoVV3pr1me5gHT6u3BNfoUdbQ++FvnYXG8PBDqmVzNNc9U6uv2Bp0Tev56fQqtJqK5xf78VdG8LK9lhAA0aJqEppdleW2lAx0TXT9en+KS7lOSebJNIqqa/oJjXO+7+vvpeJEvTVfxP88QYh2TX3/+fa8H55l8eHK4f/lsTIdDBwDNnFsGLwz2E/OXznUKwiNEd8+o5UFsDbo9vwMApiA2mjmjl2xOovmc011HLA/rGTaSliGDnaOpZZ5JpuK7UNRJl9CzzgMoKtoIU4lUQAVempsnpCFe3nNa0ECYuWZHmCubdkZwRTVOjruyvX5v+LBbW/IN2lvZ2h30k6y1pUU4fummms3PrLZUkD+UoWvpdU1NTTXK2q2haXq0vR5Nk78pvdsfFv8fe+8eHlV1/f/PVx9oa3/IU7Wftrbf71grapVLERUEIYQECBjwVkQL1VYFrUWtH7WD4RK5X0IAb3hDrVQDqMgRAZFwEZSL3FQiKvdLQEQDhEskiSHr98fJnllnZSZZe+LM2WfOej3Penwehz2ZTNbeZ7/3Xpdookk9NPDmmj4s8ENZ/R7qgAJvrmnuH67IWxe4bUApWIMAACAASURBVFQwZJ9o67CV9CWOFmEQjYUkb5pbCEptJJSpCAP18Csvj4gJfNhAIxPe3FAc60c4oAVkcIQBDrGkxQP/RKpl0wct3twr9pNQYm7BPVowKNphh3oN597RzTuuoVAXOXEW3MPFnoKh2oImGtEO1uhhRzRKyyodY1SLr/qEF62pEK27gHoNp2XQ21tc/bku6I0j3QDGQlUVVkYL7kXbOALU9mfaXSAa+EZeGae7AK2pkE6iTGJB6wBwuwtQQUEPN1VVbLoJpwUkZ6zezRLoKmw22noDEOkAgm+0q6JswnG7MRyVg9MkqD83j1LrQ72Gw99pfYobotT6UK/hQyW6zmLxXhe0NRdudQXgFJb4+Uv9Eqe/4Oc5ff7iPPJgqHZEiKoFg9Mk6DobrdZHtPlD/bLrZKdAx1XlcSQMbccVLf1FvYbreVC/HIWK0FJ/UPM4Ut18cXidVvnwKkQcH9KpOgAq4q//9LXhfHTcChaPw2l+Kr9+yNzN4QsHtR9T6Q5KFONIEtW9Aqd0fHei3NH6Ux32qNQrNTdajXg/vE7jFASal4/TBVR6lXoG4Wcd/T1x0UZ1qKee57QgKvY/6ic9pq4MRyiu3RkR6GWnIodtdL9Ei8tyOg0lC5O0gWAjAt1nmDQJj508BS2Gvgt9n3PePtNWQfShvLekDJoNWVgrxJH2u+SEadJbTVoMDMC+ubnwsQWOHER6qxlNNI1Z8AVcOvQ9R0gVvYnDD2XFna+sgytHF8JJFCI4eI7zYT6TGcLd51nnRn8dKbhXH/QAg1sIioYLcgtBTSebHbUJxxulPs+thqvHFDr6p9MeybioVl3QAwza0k/dKtAcTVyoMNqDdu3OEvj9YGf+Ns1p4xbcW0XypqMddoxZ8AU0G7LQkZdPD0m4haCGx1lwD9/cBEO8aI14bxVOkJQWlbtan/CiKS3RbhynFm6Di3IWOFqU0dtb7mEHvXGkVa9j0e9FZ0shWnBP5VXSitHXE3/mVMSPlh7Egfaipz24Y0H9mdtdgBaeHDHPuXaqQ5R2Y5c4xCH159fW7mEJdBqWvZYcbh4sPQWXD1/k6MRBoxuUMFGcqqwKH97h/G36N4hW66Pg473w+8HOavL0oPimKLU+Rs/fAhcPWeg48FXClq6z9UEPQmeQtaHqdDV0nfwB9Ji60hFWTtdZXOsDV/UfRCJTaCoRXt8A7Bv7ZkMWOqqq03U2Wq0P65P98PvBztoOtD5F9ykrHH6CDxPHo24Mr5K1IVqtj/te3wiXDF3oOKyhhU3HLIi0YKTh1SoiRD2Pm+cuCkfnqHx4dQPdGrWXU3UA1PP4+qc/clRmV3UUgqFImzhcB0BdKDz8xqfhavNqP6aq16voCDz/1YUCjtQ4fLLC0d1GHQiov7kq/NlsyMKwGMe38jRFbO6myN9O3dir9Q+nJ9HWmvj50qdG0KtLIVoQVR2C4AsYFYXVccKycCj/ut2HHb6iDlhp6sgfyeUTp9NQsjBJGwg2ItB9hkmTsLKyEua8bd+KYmirIPpQBrBDCWleWXMSdswJ0zxEHua0GBj+eRi6ybztheg3xHQc3ejjh7Kiurq61uEC3ehzQ7jpRn/DHj2Bvps8FLmFoHA1+mBoPtzOLARFK8uqTTh++EX7fmjqAN541cWNJNeXbsJPn66GQ8dP1fI1tVlRVnKi9kk4/dvTMFZuwb01pJ1VrMMO+vPoIQm3EBTetAVD/HQK2qeWfpexoJEveBMbi+8rnKHEKjS2PuFFaypEu3EEqP1d0tvbh5mHHTT/kVa9jsXtpPIwbfFVXR3dL2lo/C5GwT2aZkBbfMWCbphpD+5YqNaNynBLpLqghSejHW4eOVlRa20YGaU+BUeg07DsaIeb0Z5D9JaMbsIrfjhd6//R0PjWMWp9UL+k62y0VKto42g+L43kigXNXY9WjLPqdHWtZ6/KV1ZGC+4dLauAQ8dq+7MqNqZsa5SIEPq7fXfCuc5GK7gXbRxdZ7OmrqzlJ9G+L9UXWxk9ZACw5yv9eXSdHbvwC8e/x+1k1TxWFwqXDn0vHCKvbn1pZ4tgKFIHABdgU2uLijKjzwlcB0BdKDw4c1N4X6ZS79RhuhL2uOCmul2fjPxFddVRheJUTrvKF8cpZapWSKwia/QZrwSxilp89M3I+kyjpvD6oA6V1ZylBVGrq6vh2+PljogidUhy+fBF4boXG/Y4Bfrp0/Y46s/08onTaShZmKQNBBsR6D7DpEkYa5NEi/NEeyhHg95qcsI0j5Y58y9pMbBY0HCrfi/ybohpuBV+KNcFDS3E+Vd18XfSAxjfCnKgEQbcQlDLSYQBbT0TC3qAoSpp17ehptXfcRufuqARBrSlXyyoj3IetLTTALfgHvU1btVrmlPJLQSliv4o46ZT/I10GuB+l1TQfBflsINCb5jCLX7q8RNaUyHajWM06O0t3gDWhaqsrOz5FTyBjitbB0PzYckX9VfEBwC49XlnFAMO54wFDcumhediQdcG2oM7FrT6O07LqAtaeDLa4WY0aMXy2ev2sQQ6bRtIu4nEgoZlc9YGGkkSrZtINGhYNrcYJy1yOjLKYUc0aDcDbjHOPiT9hVOfAqD2M50TEUKf6ZcM5RXjpG0Dez4RW6DjtZQ+0x9gpr/QZ/oEdCsPAOEuNngeq2KCF+UsCNdWULe+9NAyGIrUAVA9vbtPWRE+SFVRZrTYI46SUwfm972+MSzEVSTG3E32fFQHrHj+q/z48SjiQnXVUQcLSqyqfHH8+VWdCtwGs7q62lGTANf2Ub+TinrBUS24JgGNWqMHobQrQTSwf6mw/417j7DWFHqwjzsduI1J2kCwEYHuM0yahLEWNNoqiPNQBoBwERNlHGjVXVzUoy7oQ40bwk0Ld9GHcizyFjlDuHH+VV3QHsCfkor49UFbMHEPMHA132CIn2dKbyPUAUZ9Dz+a209zdmNBc325Bxjq9F/nQUtvALgF9zYSQcOtek037zQlJBZUVHLTKaio5H6XNDXlCCPsj4pKlZpSn5/Qmgp9nuUJGnp7i3tw14UKA1XGrYhPuzbQG8dY0J6/nIr4NCw71o0jheb69ohSET8aNIoh2o1jNOZ/5kzZ4B5u0vSXNzcUszbTNCybdhOJBQ3L5rT7BADHjSm31gcNy+YW46RFTrmHHbSIJ+6tXhc0/QUX46wLVbxL2c5v698L0PSXP0YpuBeNT0j6S/aTH8YU6DjFhR52cItxjifpAqpdmgKLOTWPcRSWaoeJb31p+0+V6qGiA7pMWh7+W6gbaDqPcZScqrQ+cMb6cOi8yoentVHw/FfRATh65XjNM1JFAyqx/b+z7cNOvA6pwzjaBhN/J7i2jzocVq3g8AEKbnlLixDiuhXc9fn06erwobL67yf7jsZVePIko9NQsjBJGwg2ItB9hkmTMNaCRlsFcR7KAM42O9wwzR9IkapMZh4lLZDEDeGmm0z6UI7FE+SGGOdf1cX9pPq7qsDKhaYApDMPMFbtcG4co7WeiQbt3a1y/ep7+D1HNo40ZzcWNAWAuwmnh0icln40z5S7CVe5hcq4Va9pGgZt6RcLKiq56RRUVNLuC7GgeXmqsFFdUFGpUlPq8xNaU+EW5o0jvb2lPbhjQUOCadXrWKh+vsq4N453koiZ/YyCewDOKAbujSPN9b3uSZ5AV4WulHFvHGm+9Xjm4ebUQufaOWcjT6DTsGyuP9Ow7OPMWzJ8UBWtm0g0aFh2rFQrCg1r5h520Boqs5mRXPTgiNvukx6E7o4jZYNbjJMeHPV+KrZAx1EfdG3g1qegB0e4DR4AQCe0n1HzGBePU892fOtLvy8VVq+iAzpOWBaOslHtX+n3hevwqOiAv7+yLnzjrS5M6PeFC26q6ABcJFOJUXowgWujqAMGlVJEo3Jw2gk+hFdF6ZSAx4fR+FlB55XqCa+MWxD1SnIT/lkxT6DTvS2uo+M2JmkDwUYEus8waRLGWtBoqyDOQxnA2dOaG6YJEOm7HgzVPrGNBc2/5N5q0oIl9KEcC3pzwc2xfpi0GKIV8euD5vNxDzDWko0jN8+UhhKrA4z6Hn5048gNCaYbR+4BBq3wzHnQ0o0Qt+Ae3QhxoxHo34BbCCqfbBy56RS4n7GOr9HaEdywP3zjqCqI1+cntKbCrc/zBA09WONGI9CDtVeYG0B6sMa9caSHJNw+u1gccm8caU2FaD24o7H9kPOQhHvjSPOtJy7iCXTaUsz6ZD9rM03Dsrn+fMVIZ1g295YM37xza33Em2pFU5C4hx20uNxbzG4ZNNWK2+6THoRyIkJoZ4hoFfGjQdNfrn/6o5gCHbdgpC1FufUpaN0UXBkewClG1TzGh7xqruNb31411cyVqVoAuD2b8mt8A4075+B2iSpyqP/0teHWourCRIXbK+uN5r865MUV+tUzkq6JuDaKmjuqywCNysGRGO8VRQ7h1YGmOkSgh9FqDBXotH0t7UoQC1qfomh/aVx1LWhdAjcxSRsINiLQfYZJkzDWgkZz/zgPZQBnKxdumCaAM2cwixmmScPCuLeaNOyYPpRjQVu5cHOsaSsX3FudA83n4+aZ0ny+aJVto0HDBfNrqvPW9/CjbbC4IcF044h7q9dFF3ISznnQ0o1jh/G8TTi9ceRWvaZ/A26eabQbRw50s8P1NVo4hytomiFRqSoI1+cnNG+aK2jo7S3twR0LmnpBq17HQoWvhgUN88bxn687b94PMfvsYnHYnHnjSGsqXB+lIn409pY4/wYqxLU+qKjkHm7SlmLzPj3A2kzf9oIzLJvrzzQsm9PuE8DZupFb64OGZXPrU9AIJ24kFy2WyO2WoXpmK+MWkKQ3jsVH9FM2uMU4aVeCG5+JLdDxuvFekfPwjluMkx4cPbHE2YLxBlTAVM1jXExQhXXjqJw7SB0QVYdnywH7GXLl6MJwIUl8A61Cw4MhZ7tE1arz1ufXhHPi1YUJLWyI578qDod73Kt5QA/TcbqQigBQhxc0Kgc/Y95HUXIP1PwcFY1FD6PVGCrQ6TrLXZ/p2vD5AZ5A7x3jAMUETNIGgo0IdJ9h0iSMtaDRVkGchzKAsyI3N0wTAMInw8GQXRiGA709upsZwq2qk8Z6KMfiv2ucudkLmDnWtPo7brXDAfd+DYb4Bxi0EBQ3z1QVnlGmDjDqe/jR4nIrmCHBNAeNuwnH0RrB0HyoZDxoaSEo7iZ8G8mb5kYj0M27KrhXH7QQFDedAm/GgqH4iztyw/5wvqWqIF6fn9CaCtzaEfT2lhuN8PwKZ+RLtKrX0cA3T8FQ7fZ/sfjXLOeGk9tnF4dlc9v/0ZoKN8aoiE+hfwNu+z9V6EoZbq1VF/Twbv5nX7M20zS6hrt2xgozrg8cNpsWo5sIhUbX0LZ7saCHd9zDDhrhxI3kotE13HafdJ09wEzZwNE1sSriU2hU3J+fXRVToONq+YVbaDFOnkCnUXFPLXXuBfBtsZrH+BmiXsdROaq9mTJVRVw9Q/404v3wPgmngeF6C7gOj2rVefO0VeFb9r0lkf0YLmSHC26qZwgOIVfPSLqXwelCmTVF3lShUhqVg/czhaizhfq91d+ddiVQY6hAVwXrdNdnehD65cFjrDWFdtngFDJOFiZpA8FGBLrPMGkSxlrQ6CLGfSjjCsbcME0A58YI51HVBd2ccm81acEv+lCOxRtkY/ReEU+g0wrG25iiSUGL6HHzTGkRvQeZeabvkOJFqsdrfQ8/erPDzXGkRfS4opKGqnEftLilGLfg3k6SN82tek0379w802nL40unoJtDbnFHWtmWe+OIN4cqsqM+P6E1Fbi1I+jtLe3BHYvpJPLl9bW8olqD5zgjX7g3jlTYR2v/Fw0cls29caQ1FW5mVsSnh5vcG0eabz21ML7DzfeKeAKdRtdsP8RbG2hYNufwDsAp7Lm1PmhYNrdbBl2fuYcd9AAVV9KuCxpdw233mTXVGU33DTMiBEfXtBnFE+g0uqbPc6tr+YmaJ/hgfRlZG7j1KehN8jPLtztex4dtOKpIiVDV+/tVdOtLw+YV6vDh8uGLwhcguHUj9nWcxqYOH3o//VH4QBRHNOI8eXxooQ4f8PtW1TwjacFNnC6kbpjV+tebROXg9RT7kOoJr4xGi6n2a2NJMcQcEmHIXZ9pD/ut3xxnrSm05o1JmKQNBBsR6D7DpEkYa0GjrYK4D2X8MOCGaQI4N1T0gRALmk/MvdWkGyr6UI4FzXN7n1kEjd7g7WAW3FPQ37M3M8/08wPODSC3cA7N9VU9Xut7+NHq+NwbR1qMiysqaRoGF1yMi9sxALeJCYb40Qi0IBq3YwD1GW46BRWHnB7cALW7L3AFDb71VZEv9fkJranAFTT09pYbjUBzdrlVr1WbImXclnXDycaR22cXH5Jw2//RtYHb4otW2ea2//uURIQ8yYw+omkz739+kLWZpmHZ3GKl6aQ+RRXz8A4XOeXW+qDRNTg3ui5okVNuJNd7Rc5UD5zHXBc0soPb4SH7SWdI8KHjvL0ALjzJ7ZZBIzv6Pl9boH9z7BTM2VjsiIqgHUu49SloZMezpAf3wdJT8PyKHfDhNudhs6oXob6bGejWl14cKFSP9IuHLAyLYFyn5RFUqwbX4VEHkz2fWBn+ubjwJA7Dx/NfCWksSNVtPk0JwPnit9Tkx6uQ9RtIVM7J8h/g1dW7Yc7GYkePcbpe0vX52+Pl8Mb6fbUOf2mEIbdjCb342H6IJ9BxxN6FGnWSkoFJ2kCwEYHuM0yahLEWNBpayH0o34fCjrhhmgDO21D6QIgFDVfm3mpSsUUfyrGgPa1xeFddvEk2p1zRpKBV7rl5pnQDyC2cQx/eqsdrfQ8/unH8eBdP0NBiXNxNOC7Gw+0YAOAsxsXdhKvNlTJu1WtaxIebZ0pvfbnpFPTWF4dC1gVtPcMVNPjWV0W+1OcntKYCV9DQ21t6ExML2jaQW/VatSlSxu3BTTeO3BZf+PaW24Ob1lTgtviiLfJymDeOVIyqw7v6UGG6eO3kbKZphed4ipViYaIzLt5ipdxUKzqOG8lFW2tx21nSYqXcbhlYAAZD8+E7ZkQILjzJ7ZZx6Lgzuua2F9aw/ITm83O7ZcwgkR3Pr+DtBVS9CFVMl9764kMNheq4cOFjC8K1enCdFtxaE9eZUW38uk7+AJrl2M8uXHgSt9bEBTdfrUk56/Ps6lqfhUYj4XQhlVev3vcmZlQOXS+567MKpQ+vz8yOJbROy45vT7B8Be83LsoRgS7UjQh0n2HSJIy1oNFWQdwwTbwJ+BMzTBPAmfPOfSAAOG9D/8ksgkZDbHGLlLqgm4ClX/IE+rIvnQ9DrmhS0II73O+HVmrmhrHS9j9q01Lfw48W3+OGUNKbnT0lvE049hmdBy2+2eEW3KNC+yFm1WsqRvOZYayvkJsdbjoFvcXg1o7AN4c6gganpqjIl/r8hNZU4Lb/o9WyuVWvVZsiZdyq13TjyBU0dOPIbfGFo4iuYt440kPKv7zIq4gP4AxB5goaGoLMjT6iIcjLvjzE2kzTsGxusVIals0FFznl1vqg3wk31YoWOeV+l+vIPOC2s6QhyNyWdTTd7chJXkRIa3R4x21Zd5gUPez34lqWn9DvhFufooC0FOX04AaIFBNUnUTorW//6Wtr+V4JihxSFxK4dSOOmsKV01UnkPS85eH9Do5oxFFTeP6rlDN1W48PsT/e5fy+cLqQqlXQ93lb2Pd5lnfoN3bBF473HLeQtz7Tlm/cjiW08OSu706yfAXnvF+sUcg4GZikDQQbEehJYtq0adCiRQto0qQJNGnSBNq1awcLF0YmaFpaGgQCAYf17dvX8R7BYLDWvwmFQlqfw6RJGGtBo62CuA9lnBfEDdMEcFbk5D4QAJxi635m2PFxIhC4D2Va8Gs5s0o5DQvlbjIxuA0d9/uhNzTcwjm0GJf6fup7+NFN0iZmCCW92eF+P7hHsk7HAHyzw92E05sdbtVrWmWXm7NLb3a46RQ0XJDb4gtXxL9AIxqhHQqNVwXK6vMTWlPhnhm81BRa9JDb4otGsHCrXtObcK6goRvHsgpeRXwcls0VNADOmgrcgnsAzsr9XEFTQtITuNFHtN3g8q94Ap0e3nEPnPANpk50DV5TuMVKaVg2N9WK1gHgfpe0rsViZiQX7ocdDPFb1imhpqy0jHfghA/vuC3raHh4/+k8gU7rytACZbGgBfdwNXbO76ZSg+itL76lVeCDSVUZH7duxOsUrjOjfrdrJywN7wNwRCNep/D8VzVz1GEAbntL6x+MQvniqo6JmkO3MNNmVFs3Zdx0LtpSlHuASuta7CnhCXT8jLx0KL9OUjIwSRsINiLQk8S8efNgwYIFsHXrVti6dSvk5ORAo0aN4PPP7cU8LS0NBgwYAAcPHgxbaanzIRYMBmHkyJGOf3PihF5OsUmTMNaCdh+pkMl9KONTVG6YJoAzTIv7QABwbjK5RdBoyDj3oUxDxrlVyml49H5mwT3MRTkLtL8ferPDDWOlt13q+6nv4Uc3jlxBQ6u4cr8fHLqn86DFPsMtuEeFCbfqdXV1taOaMTdnlxbc46ZTjHzXeevLbfGFQ3t18vJwWLYqUFafn9C86X+8xhM0dFM5iVn1mhbV4hbcy1vk3DhyBQ09XOEW3FPVk3UEDYBzbeC2+AJw1h3gChp6uMINCaZ/u5XbvmVtpunhHffACUfX/EHDn3HtFW5PeRqRxU21omKU+13SgpU4j7ku6OEdt50lLarFjQjBh3fcdpa06OHtL33M8hPVY1wZt50lLZbG7cGt5o7qfkFvfXEdCsX3FVWO7yMYcrZuxJF22PfU3MHfJ04zwAeCuOCmWvfUYUCznMghNo2uG4PC0dVBjhqHw+brQrV1012faU92bscSWtdi3+Eylq9MQDf2l2vUSUoGJmkDwUYEuov84he/gOnTpwOALdAffPDBOv99MBiEKVOmNOhnmjQJYy1o9OaC+1DGFUy5eWcAzpYZt73AD9PEhZW4YccAEM7l0nkoU8HLrVKOH8zB0Hw4WMoTTRjcJ577/dAQSm4YK81xVN9PfQ8/WhCNK2hon3ju94NvdnQetLilGLfgXmmZczMdeosXjQDg7G/Nzdmdvc55s7PsS160xhgSZsjNF8UhwXgjVx+4grAqUFSfn9ADMm5qiuojrIxb9ZoWd+RWvaYbzi0HeOs13ThyW3zhOhzXTuALdFxT4W/MFl8Azv7Wo5iChobUc6OPaH/rVdu/Y22mQ285D++4B0434+gaDX++HdVe4db6oId3XH+mB1Xc75Km2yxjRnLRwztuO8vbST0aXM28LnBdC247S/qd/O1lnkCnBVG5BSStT5yHd9we3GrdU9FY9NYXrx0KXC9C3cDjQqo40g77nipqi59bOOUQrzd4/qt1Tx2i4nBuujfA3UXUM+TqMfZn5KbN0Nag3HSueDuW0LoWxUd4Av1JdCCgUycpGZikDQQbEeguUFVVBTNnzoTGjRvDli32Yp6WlgbnnXcenHvuuXDZZZfBww8/DMePO9u6BINB+PWvfw3nnHMOtGrVCkaPHg0VFbzwb4VJkzDWgvYIubngPpSfQ31FdcI0cR5Vvxf5YZp4E8AtggbgrD7NfSjTkMRVO3gCHcDZL5q7ycRchkL5ud/PN+RmhxvGqorS0O+nvocf3ThyN4A0b5r7/eAetc01HrT4UIe7CadpEdyq1wDOUE9VcK8+aFg2N52C5vNxU1Nw7q1OXh4Oy1Y3LfX5Ca2pwE1NoQXKuOkCtOght+o13XB+eZDnzwvIxvEHZkV8HJbdidmDG8C5NtzJrIgP4Pybj2EWdAJwrmXc6CMqCFbvKGFtpmlYNrenPD68u2Qo359x1XhuT3l6E84tIEkPO7jfJT0s/IAZyYWLkAVD/HaWOLotGJoP31fwDpw6o7WB286SFi+86z/rWH6ylawN3HaWdK5ye3CrlCBVx4GmzeAaIgq87rWoEfa4dSOOtMOFctVtN07Nwus6LviGC24uqqkl02aU/fzBUWZHSK4/ruehDhfUwTI3beY50lN+SiFPoNNWd9wDVBrp93Xp9yxfwT+P284yWZikDQQbEehJZPPmzfDzn/8czjzzTGjatCksWBAJf3vhhRegsLAQioqKYObMmXDBBRdAZmamY/zkyZPhgw8+gM8++wxefPFFOO+88+Cuu+6q82eWl5fDsWPHwlZcXAyBQABKSuxNiptWVlYGlmVBWVmZ4///m7RrOnbyFOv9XvkwskhfM3YJ+3MMfTtyU9LvxTXscel5kRu8h2d/wh6nToeDofnwn492ssYcPeHcZH649Rv2z2s/LhKe9vWRE9p/pxbo4dyf+f0cPHrS8Xlzrc2scR9udeagv7pqZ52+ouzbUmeEwZbiI6yfN4xswg8yv5/+SKBfNvw99ndJ86Y5Y46ddB52DH7rU/bPuxYdIk1bto015s31zhD3pV98zRo38T3nJrzkWPS/FbVeT0XE2qVDF7J/twx0C3tbTUuk+vyksrLSUVPh/tc3sn7W1q+dYaxTFn/FGreoiNygf1LMGvfUEnKDzvTnws+dP6+8vII1rjfqSpA2cRn7b4AjNO585WP2uJunRcLAR7/7OXvcn1CKyPSVO1hjviFr0apth1h+MpSsDd8cPcn6ebe9EBHofxzGXxv+8d+IQL95Gm9toM+FBwp4/lxZWekocsr9Lk987zwoXvbFQda48QvIDfp+nj/fTQT6ie/LWeNwXYv0PJ4/V1SQDg+vfMzyk68OONeGsfO3sH7egk+dN+j/Xb2LNa4b6RLw1vq9Md8X/3+VjqIi4tZsPxR+DT9jej25Mvz/t39jRwfgSJnv0Lq+aXeJ4/tS///9mnVP7R3wM/JEmfN5Nn5B5Pt6eqm97qnaFtz9xvMfbHe85+T3v2SNm77SKezf2bSPNe6jbc59SnHJcZavvLoqItBbj3yf9bOSZSUlJSLQDUMEehKpqKiA7Vb7XAAAIABJREFU7du3w/r162Hw4MFw3nnnhW/QKRs2bIBAIAAbN8YOWXvrrbfCYjsWubm5tQrLBQIBKCgoAMuyjLQ7n5jnfAC9zRuX88I74TFXDH83rp+XNW4ee9w1I94Nj7s1nz/uqtzIuH8//w5rzNtzLcd3kj+D/322ezzy8157U//v0Xp4ZHwP5vczd64FFz8WGfe3qbxxT7/u/D1DzO/nrbed456fyfvdBj7p9LXXmd/P4y+94xgXz9+iy2iej86da8GFgyPj+k/m+1o75KMPTuN9l6Nfcf5uE17ljXuG/O1mzeF9xrRRkc94cQ5/3uJx3cfyv5M/5kTG/XkSb9yMN5y/2z+f4X0nM99yjhv5Mm/cI885/wZcf540w4rLL7uPjcyDqx/n/w2uGx8Z12sC/2+Af95dT/LH4bXo4ed43+Ubc5zfyZT/8n7WALI2FLzFG9d7wry4/PnPeZFxGWN4496ea8HvQ/r+bFkWNHtM/7ucS37eRObacP8z8flzn0nOv8Ec5l4Arw06/nwpWhu4/kzXhruZ/pz3qvM74T7rrh35rmPc8OnOcW/PteD6ifPgH087/7/6e19Q8/ej8+COqfOg7ePvwpAXI+Nenu383YKh+TATzQP8Ov6+xv/H/t0uqvmZl5J50B49lwag7+thsu5x92N03H1P877L0PPOcY+/xBv35GvO72XGGzz/GvJi5Oe1GMr3y2RYQUGBCHTDEIHuIhkZGTBw4MCor1VXV0OjRo1g1qxZMcfv378fAoEArF0bOwzIizfo05Y5wzvLTvFOzd/ZFMmd7ThhKftzTH4/Epp7x0tr2eN6oTDNf7/Jv9XsMTWS7/n6Gt6peWVlpeMUe+2Ob9njstHn/LaUd6sZa/zfXuZ/P/M+iYRKj2Leku39zhku+Pqa3XX6irKKigrHzei2g0dZP4+eoH/HvPWtrHSGenLH9H0ukp/a59lV7HE4NH7oXF40QmVlJVz/dORm9IUV21lj1u101gFY+RU/WgPfHnIjX/BtavPcReyfdecrkfzUv05fw/KTyspK6Ixy1x+atYn1s74/5bw5fGrJVvbnHPXu5+Fx7322nzUGz51gaD5s/Zrnzxt3R1JEfj+Y75f3ozocGZOWs8d9XhzpnjDw1XXscQNejdyMjl/Iu3GsrHTejL7CjD6qqKhwVJv/eOe3LD95cYXzVu7wcd7aMPitT+Py50ffiNRe6fscf23A+cFcf66srIRWKNWKG8lVWemMmuBGchWs3e34LrnrM547wdB8OMWMCPn7y5G1ITOf78+dULvBga+uY/lJGVkbJiz8gvWz8NwJhuZDwdrdrHF4TQ+G+Le+OEw9GJoP63bWv4fYf9hZ2yUYmg9HTnwffv04ug2/Z8b68P9f+ZV9w6zmXcvHnfPgkz2Rm/e89yLfF/UT7n7sv6udrUGfLORFOM3Z4IwWm/8pL8Lpi/3Oyv0Hj5xg+cr8TyPr+tWjC9l+mQyTG3TzEIHuIl26dIE77rgj6mtFRUUQCARgxYrYvZLfffddCAQCsHfv3pj/hmJSnkllZfScHZoDW3Wa1xcZVyLl5p0BOCuR4jyq+sA9WrlVygGcRYRmM/tuAoAjvHMjs40YgLPieOn3vIJ7mDvQZuduZt9oAGeeFrdvNG0N9mZNAZxYvoLBG0duv/d3PnWGBHMLEgKAYxyX++IsSIiLeHGrXgM4WwhyCxLuLXGmC6zZGTtCh4J/P26BMpyz2/Jxfl4ersD/95r8Z46f4Pn36Jv82hG4Av9zzLZUAM6iTdyq17Q12O7vTrLG4YJoOhXER8yLhCB3mxz7mUPBvsKtIA7gLASaz6y4DADQC4Xiv7aWl7ML4GyJ+em+oyw/oUW8uLVQcOsmHX/GbUJ1aqF0m7wiLn/GqVavr+XvIXBdi7XMtYG2z9xTwvNnmltcXc3bC+C6Mt2n8P35xmc+cvgzx08AnHVluAXKaF0Zbosv/DwPhubDws28uhZXoN7wwRCv0wnNFw+GarduVHPrPlSgcD1pe/onkm+Na8bggpu0qOZd/+HtN94gLeu49Vber8mVV8ZtKUrrWhw+WcHylQ9QEdxrNOokJQOTtIFgIwI9STz22GOwcuVK2L17N2zevBlycnLgjDPOgMWLF8OOHTtgxIgRsH79eti9ezcsWLAALr30UmjdujVUVdmb3NWrV8PkyZPhk08+gV27dsHs2bPh/PPPh969e2t9DpMmYawFDQttnYfy6h2RTW2XScvZnwP3tBygIUBxC5ihc3lVygEA+k+PjOM+lAGcrYk+3cdrI0Z/3gnmJhPz0OzIZprbNxrAKTLyFvE34VhoqwI4nIefKkgTDPF7FtOidNy+0QDxCXS8CdfpG42L0nGrXgM4iyzNYBYhOkHaDa3bfZj983JQVXxugTI8j1qPXMz+WbgondrIcfxkACrGNXgOvyI+rjzOrXoN4BQZ3KrXtPL4vsM8f8bFnpppFNx7elnktjhrKq/9H4BTZHAriAM4uydwCzoBAPR5LiJOCj7mi0p8y1y0v5TlJx9uc64N3JZ1uEgXFSZ1MQpVOtdpWYfbs+l0eLh2QqQ+xax1/O8Sd09Yz1wbNpFe4Vx/xsLrAo2e8rg/t44/3/Wf9Q5/5gp0XLCS68+0owQt9hYL/CwIhubDe0U8UYkPZNQ8qA9aoDTaPFDFcgehgpuf7HPm5V9B1nV8EI+fZ0u/dB7kcPdjtJ0l9wCVznFuS9HD5ODiaBlPoK9DBxfc9n/JwiRtINiIQE8Sd955JwSDQWjcuDH88pe/hIyMDFi82F609u3bB506dYJzzjkHGjduDH/4wx/ggQcegMOHIw+/jRs3Qtu2baFp06bw05/+FC655BLIzc2FsjLeg05h0iSMtaDhlh86D2U8LjP/A/Y43CpER4D+/ZWI+BnObCMG4BQI3IcyADjCOzcX89qIAThFmo4AVYyeH9k4cvtGAzj7w+rcknVEYYaq7Qnn4YfHcXsWqzYyuptwgPgEOm4FqLMJH1SwKTxOp+o1biHIvXGsrq4OVwgOhubDhj18gT5xUWRjzD1Y+ytqpdRmFF+g44q4aiPH8ZPBcyI3749pRL7giJnpzKrXAACvro6EbXKrXtMNIPfACY/TafFV8HEk1LPnE3xBgw9zdA43cdutJ5bwKuIDOKN5dEQl7rjx+QGeQKet9bgRIfNQVA4VJnWBeyTfodGyDs9xnQ4P+HmiE8mFo3k27OFFctGoHK4/48P6CzUiQnBUnI4/49Z69xdsYgt0HJWj4884Kofb4ou2nuPe+qqWZ3ge1AdtPRdtHqgCkw+iDgJF+52t59qMqt32Vr32v7MjUR+rdjgFM3c/Rm/eX1jBO0DdsMd5cMRtKUq/l9LvK1m+gr8Xbvu/ZGGSNhBsRKD7DJMmYawFDff81nko43YnOmGauKeljgC9Z8aG8DhuGzEAgAdnRsQW96EM4GxNxO3zDQBw32uRDZyOAFXgXqE6t2T4FlDnluz6pyNhhqrtCefhh0M9ue3SDpF2cBU/8G59AeIT6DOQWNPpG537zufhcdw2PgDOUM+ZGjeOuNq8TjoF3hhzwQddV46uvZGLxdubIgdr9/7XnrccP8GHCEPm8gXNwBmRg7WXP+ILdHwLuHIbT6CfPl3tqKlw4CjvwOn7iqq4/HIRCvXMfvJD9jjcmup2jQOnSSgM/KmlfEHzj9cia66OqOyKKl9/efAYy09oq0huRMgqFJUTTZjEAh/e6bSsG46icnRSrbKmRp4nb2pEct2AwsA3MdcGGpXD9Wd86K5z4IQP3XX8GR+SPDiTL9DxobuOP+OoHG6LL9p6jnvrm4YiH9Q8qA/aei4Ymg+VZB6o9fuhWZ+E/x9tPXdVlHU9mq/Tm3fufmwRCVXnHqDSQzhuS1HarvP4KZ5A3/FtJKdfJw0zGZikDQQbEeg+w6RJGGtBK6twPsy5YGGvE9aGe3nqCND70a3miHn8sOPBcyLhndyHMoAz94zb5xsA4CGU76kjQBWzkcDg9tkFcOZpPalxq4A3IAtq8us4Dz8s7L87wetZXEnCDLn1DgDA0aaIC+59q1Pv4MklkcKJE5j5/ABOYa8jaPBhkE46BRajXHBYadsx/Lw8nM+n8h85fvLSh5EQZJ3IFxyW/erq3exx8z+L/M1Xbf+OPQ6HZX/DPHCiG0cuG/ZEQi97P83rwa1Q4/o+v5o95pnlkZD6Z5ZvZ4/D6TY6orI3Whu2fXOc5ScVPzjXBm5EyJcHI5v+aMIkFvg70an1MbUwsjbopFrh70QnkguHWHPymAFqR+UcLOX5M36m66Rs4PonvZ/iC3QclfPQrE/YAh1H5Ty9jO/POCpn/me8XHJ8MRAMzYelX/IEema+sz0btxc9LrAY7Rn58Bv2ITC+Cd/5rbO4XLR1Xb12I+q7/tVBp7C/j7kfo6Hx3APU3d+ddIxbwYxwAnB+LyfLf2D5Cs6910nDTAYmaQPBRgS6zzBpEta1oMWzyfzuRCQfUkeg41zp+wv4AlQ9mIKh+TB6Pl+g44JM3IcygDMU+KuDvIcrgPNAgHsLhMEFfv6FTsnrA4fb6oT94Vvf94r4Av0WlJ965GQF++fFswkHALgMFZ7isgb5ms4m/LW1kToJOvn8OBdTR9BgX9NJp1i85Rvt7wRvONtpFM7B4YIq/1G3+JdO5Au+9eXm8wM4N4+rd/AL7uFb30PHeYIGIL61cxfaqN7wTHwC/XoNYf8yytN+VqPg3hDUm1xHVOJChNsPnWALr3i+y0PHIzfvOgIdi8OBM/hrwwxUQ0XHn/GBr04kFz5A1YnkwlE5XH+O97Aep1fp+DOOynn4jU/ZfoKjcnT8GUflcIu94XSnYIhf1wJHTNjzgLeHaJaz0DGOPiPHLvgCgiFngUJ8sBIMRS+Ipl5LRzfJdNwg5n5sxVZn5xFuQVQaJfPhNv4BquonHwzZkYkcXzlaVhH19zYBk7SBYCMC3WeYNAl/bIGO84I6TeTn93x+ILLRf1DjhhjfqI3VyAvOR1WduQ9lAGeo+jbm6TeA8xb1tMYNsQIX+MGn5PWB/x7xikqVX8d5+Knf84qRi2uF4dUFbj+jA66qz2UbCv3TqXfwXlHkFlYnnx8X/9IRNLjKts4mXG1AdIpj4bBSne/y+KlKuHSofUiiKgFz/GTltshmTifyBYtKnQriuHglt+o1gPPAiRsRAhDf2ln6faQY1HVP8g838c/TORTFkRbPr+ALGlwPQ09URoTQru9OsoVXPIdwOCrn8uGL2ONw+otOqhXOv9Xp8ICLM76jEcmFU7Q4ecwKLBAT7c9Y6N00bRV7HM55f/RNvkDHhys6/oxz3hcxc8lxRFwwxK9rgTsgBEPzYee3J1jjcAeEaH8DVXMBV07HN8XBUPSCaOriYO6myDzGlyzBED9ibx2pGj+DGeF0jBTB04lwwvUDyn/gCXS8Nlw9hn94lwxM0gaCjQh0n2HSJKxrQWsRp2hSY3Ta2xwsjZyiPqRxQ4yF77iF/LDj/6yKbMS4D2UAgKFzI7mGO5gPVwCAsQu/iOu7VOACPzptfHC4rU6EAc5jVm2pOA+/qtPV8FnxUSgt02slh6sZ69B2zBLtcSVoA6JTVOvjXZENiE4+Py7+pSNocBEvnXQKADtygtuSCsDOt45nEw5gb+iK9peGb3U4foIP5HT8Et+86+Tz47xKbtVrAGdkgU5ECM5d54Lnqm51YTUuXSNkE0cV6FTEx4ebOqISt+TbW1LGFl64sJYOasxFOfwaKrPWReaqTqoV/i5HanR4wLUfdCK5cAQYJ49ZgVuYHY4zwokLFno6Ah1HOIXe+oztJzjCScefH58X2UMsZuaS4wizYIhf1+ImVMguGOK3bsQt5H4fo2hv8ZEyx806FdrRCqKdPl0N+0ktgpOkVgE3Ym8HCan/LzPCiaa46UQ44ed/ZdVp7aicizVSNpKBSdpAsBGB7jNMmoR1LWi4lYsO8TzMccsPnbBjFdoVDOnlBeMqv9yHMoCzn/Iu5sOVjosHXOBHJwUAIPL3GKaR64sL/KiqqtyHXzzgmwUd4vFRXHTnluf4ObvbD0U2IDrpArh4jk69A3zzrpNOES/xCnQKx0/wgZyOQMcteWav4+fz44JJ3KrXAM68Vp1DJ9zvWAc1RufWF49rP44v7PGhxUsaFfFxwcp3P+P7M27Jt+8wX6D3fGJlg75LnXE4vFpnncWVr3X8GR8A6URy4bWBm8cM4GwHd7QssQIdC71eGjnoODR+8JzNbD+ZszHyt9Pp8ICjh9RhdH3gVpbBEP/WF0fkBEP2QRUHXAuDW7S3tMx5M53GjGikh7UPzeYJdBw6HgzNh9fX8g9QL8qJ1JLRiXDCz/+q09UJTZtJBiZpA8FGBLrPMGkS1rWg4QI2OsS7+Kkxf36Wf9qOc1J1QrhxlV/uQxnA2a5pTwlfoOPiQ/GAb9d0encDRL7Xf7/J78+LC/yo8L1ECnTcJ14HnCOsgxqj02ngCMrnV+HcHNaj0L8FGpvwmejmXSedIl6aD48vYobC8RN8IKfTlgpX/H1Do+AeDrflVr0GcIrKY6f4fo/bZ+nQ0LVTp2I5/k5e0aiIj6OPdPwZhyAfOPo9ez3BBdF0iOe7xMUEdWp94MMOnVQrXOSU20sbwBmVw81jBgD4G2qRV/o935/j+S6x0Os6md9yFXceyXmbL9BxCpJOh4enlkYK/HFzyXHkXjDEv/XFKQ3BEL/VHb4p5kaE0JtwnXzri1ExwUfe4EXsnT5dDReioq06EU44WnOdRoQT7hpTXS0CXfjxEYHuM0yahHUtaLjfrQ4N3WRmaPRPx5W1dfKCcZVf7kMZwJlruO8w7+EKADAdVa2OFzVe5zYCj9PJ7d9cHAlBVuF7iRToeKOqQ/aT8d28qzE6OWh4w6lTCApX01UF9zjgYm866RTxEm+aAUV3k6Tas3HALfl0Cu7hcM9PNCriP78icluskzKAQ1l1aOja2TyXf/OON/A6RbVmr9sXlz/jG86DpafYfnIf6jGuQzzfJZ5z3JtDAGfla51UK1zkVCeSC0flcPOYAZw39sc1Dpzi6ZYBEPkb6NSjKT4SOTgaOreI7Se4Ewy3QBmA8+CIm0s+CqUfBUP8W1+8pwqG+K3u8NrMraRPOyDoVCzHtV10DvbbjCoMj9OJcLp6TGTchj18gU4j77i+ckEcKUjJwCRtINiIQPcZJk3CuhY0XKRKhz/GUdQHAN8CLWaPee6DyAZa51YTV/lVIdwccLEpmrtVF/9FVX7jRY2PlkvGGadT9Ai3Z1Phe4kU6LiPsA43N1AI6eagqXE6re5wqKFOSPCGPZHCgDrpFPESb5oBRVeg67QGw/mKOmHZuBL1x7v4G0Dc3vD7iir2OFxlW4eGCnSdPtU4KmfsQv6tL04P0qnfgQXUoeN8gY6rxusQz3eJ2wZybw4BnNEIOqlWuMipTiQXjsrh5jEDOIvL6Rw4xVOoDyC+g1DceWTIXP4NOq4Rwi1QBgDw+tpINAI3l3w8KarJvfW9G/VqD4b4re7S8yIROZcM5c1x2u4xU+Pi4xpU7X/wHL5AxzfaOgeondHvpxPhhLsgAPCfPa3jTEFKNCZpA8FGBLrPMGkS1rWg4eIpOjS0qM8fmDlWAM6qzlML+XnBeKOvU7gL57J+XcoX6G+inO54UeN1bsnwuL+/wu/5jau/q5udRAr0/Dhz9JMZ/orH3f7Sx+wxeKPELZwD4OwPq5NOES/xphlQdAV69yn8NAM8Ll/jQA5HP3A34QDOG9VTlXyBjm9GdYi3m0FD/Tn0Fn8Tjls+6tz64tzikhPlbD/JW/RV0r4TfACr8518ezwSoTFxEV+g41BpnYNiHJWjE8mFC/XpHDjFK2jUmFYaHSW+r4g8e3SquOOoL511Ftcd4OaS56PUumCIf+v7j9ec/dO5re5wKtcfh73HGgMAjpBznXQunKLz2Nv8FCRc42DORr5A74G6C3yqEeFEn1lcX0mPMwUp0ZikDQQbEeg+w6RJWNeCNrVwW1yLWDKL+uDKrU9qFO7CP08nHA6HynLD0wCct07x0tBN+F9eXBPXuNk1ub6JFOj4oEUHXAVZh4Z+l73jTDN4ainfR3H7GZ0803iJN82AoivQ247h913H43SKHuJxhRqiErcO0mkbiFuR6RBvmkFD/Vmn53e89TvwLfPhkxVxtc/SIZ4wVhy1olMbAacLjNHIQcdFTrnh1QDOqByd9JdhKFKp/Ae+QMf903VQYy4dyheV+EDzgZmb2H6Ci3gWaOQ/v1cUSRfg5pI/gVLrgqH5sJF563s/6Z/ObXWHBaxOAUmcS65zEIpTx4bM5c8DnI6CW7fVB04J2lzMbxtII5W4vhJvClKiMUkbCDYi0H2GSZOwrgUNt47RId6WYjfUtIDRET+42vjTy7Zr/Tw1TiePElcA555+Azhvj+JF9bDto1F5HCDye+qEseJxKkc/kQId31zpgGsQ6KBu3nWKFwFEqs3q3CoARL5LnT7oeKOqc0sWL7gHdEPg+slVo+28Q53UC4DId6kT4o7H6eSg417CVaer6x9QA65VoYNq46gTRQQQWRtu1mhnBRD5TiZp1O/YtPdIrbWBA04zKP2+ku0n+EBAh0uGLtQeh0WeTjV2HKExXOPgCFdj12n/F+/aMAYdCOgcOKU1sKPLBTFag9U37p4ZG9h+cgClZc1axxfoK1BaAzf95VmUWqezpuDIGnVQxQEX7NWJoMOFP3s+sZI9DoeO6xyE4gMgnchEfBNetJ8v0Gl9Cq6v4OLCJmGSNhBsRKD7DJMmYV0LWnV1NUz/cBc77EtxqrIKnlyyTas/K4AdJjilcKtW6DgOt5y2nF/oCMDO43vugx1wWmPjDWCfuM/WqCCt+O+aPbBcY0NL+ebYKZhSuBW+OcY/GAAA2PbNcXhyyTYoq+DnHAIArN1ZAi+s2KnV37oh/GfVblihcYsEYFcDf3rZdq2HOoCd5zilcCu7iq5i13cn4Ykl27QqIAMAbNx7BKYt36El8gAACrd8o1UNtyFUna6GZ5Zv18oBjAbXT4qPlMHUwm1a/ZgBAIr2l8LTy7Zr3QACAKzc9i28qpGbqpizsVirRzWAvXa+sGKnVssgAFvEPrFkm3bV/m+OnYKphdvgkOba8NXB4/DUUr21ARfY1Ln1BbCrpKtDKp315JWPdmmlJgA4e0dzqa6uhpc+3AUj392iVWMEIL5uGd+dKIexC76Ap5dt114bFm/5RkuIAjiFic7P6z5lRVyCBovReMbd8fLHbD/BXTZ0btBxlAz3kAR32AiG5sNnxTyBTovLcVs39n0+IphbPs5PF7hydKT4WvaT/IuP21+KFLPTKYiKc/N1Wori3PwtB/j7xodmO+skcX2l/Ad7j6rzs5KBSdpAsBGB7jNMmoSJFl2JBt/mPKdRiVjQx+u+IiQH8ZPUZm9JJFRdVzRjEu0nuDJ0MlA/S6dbRrLBN/bq4JVD7zgLSDZUoN/6/Bq2n+C6KTptA4v2R3LXN+zhHU6+j6ro69z64narwRC/dSNuj/cnjXz+jhMikQ86kYm42v/j8/gCHYf+6xxqPoCKF+pc7OAiiwDef/aYpA0EGxHoPsOkSej1BQ1vFl9YsdPtj5PSeN1XhOQgfpLa4A4YH27Ti67CJNpPsDhJBjgs21Tizeen1bK5NFSg3/DMR2w/wWH/Om0Dd6CCe9xQ9Q17Djt+N+5N7Kx1zpv3E8xK+ve9FgnlvmIkv8sNjny4/umP2OMeQh18Rr3LT/XA/rVwM1+gD54TKV64VSN6iBYy9vqzxyRtINiIQPcZJk1Cry9ouDiPbpE4QQ+v+4qQHMRPUpsTaM3VqTxOSbSf4MrXyQCHZZvKjDjbfcbb4aGhAj1r6kotP1HjdDq64DoT3FD1XajDhs6tL+4KEQzxK+nj3PU2o/gt61Rdn2BoPtz4DF+g56CbaZ2ih7id7HtF/BaMWGjrFETFIfUA3n/2mKQNBBsR6D7DpEno9QUNn5rrhGIJ+njdV4TkIH6S2uBCmTq3ZJRE+0mvOMOy4wWHZZvKG+v3xfWd0GrZXBoq0NMnLY9LoI/X6EWPK+Jz62+Ufl/p+N24t764S0AwxG/dqIpHBkPz4arRfIF+2wuRtmc6BSRxrrxOcdk5GyNFe9//nC/QJy6KCG2drgS005DXnz0maQPBRgS6zzBpEnp9QQOIPJT/NesTtz9KSpMKviIkHvGT1EetuTpdCSiJ9pM/P5vcVko4LNtU3omz3ScOsdZBdb2IV6C3H7c0LoGuc1hf/kMkd30Ns6hjdXW143fj3vruJjfvFT/wKunjdnw6bSnxwUqfZ/ndX3Cfd53DjoWbvw6P02nB+NTSiNDe/d1J9jhcTR/A+88ek7SBYCMC3WeYNAm9vqABRB7KfzM4tDAVSAVfERKP+Enqo9bchnQYSLSf9HsxvrDseFE/q8dUfjurZLMIFTfTgVbL5nI5avOlQySce3FcAl2nDSaOwtPpSoCLEHJvfY+fct68cyvpT168NTym3Vi+QP8nakN2i0Z7VlzMbuIivkBf/tWh8Did9JfpH+4Kj9tbwu+s8vJHuxz+5fVnj0naQLARge4zTJqEXl/QACIP5b++JAI9kaSCrwiJR/wk9VFr7utrzRXo/3htQ1ziMF7Uz+qlUS072azc9m1c38lw1N9ah/bjljZIoLcbuyQugZ6jIdDxuKVf8m99s6auDI/bxbz1xYcBwRC/kv5z6Ka4/bil7M/46JuR3HWd1ItXkPCd9P5X7HEf74oUz9NpKfv62kjxvH2H+QJ9NknZ8PqzxyRtINiIQPcZJk1Cry9oAHZeXaeJy7R7Bwt6pIKvCIlH/CT1GbfwS+g+ZYVW/3RKov1k/9HvoXPecq2WWw1h7qb90HHCMvjia/ef67H4oeo03DxtFTz65qda4747UQ7pk5bDM8u3a40r2l8KHScsg3c/4/fEBrBv+q+Gz1oqAAAgAElEQVSdsBQ27T2i5ScvrtwJ6XnL4WDpKa2fN2TuZuj91IfskHMAgFuei1S231PCD8vGAp3LjNW7w2M6jOcLdHyw0u/Ftexxs9dFhG/+4q3scZuLIy3rVmhEI8zdtD88bv/R79njTlVWwXVProQR8+xK815/9pikDQQbEeg+w6RJ6PUFTUge4isCB/ETgYP4icDBVD+5A/Um17n1bZazUFug4+J+HScsY48btzBSfK3/dL5Ax7UKphTyBfr2Q5GWdTotGHHqxdelfIFOMdVXuJikDQQbEeg+w6RJ6PUFTUge4isCB/ETgYP4icDBVD/BKRTFR/gCvXmufl7+/M8ixdfSJvIF+hNLIsXXbtdIASxE7eCe0Ghfu/9opGXdqu18gb5iayT14ptjetEPGFN9hYtJ2kCwEYHuM0yahF5f0ITkIb4icBA/ETiInwgcTPUTXDhP59a3zahCbYG+9MuIYE7PW84e98KKnXEV0f1o+3fhcU8v46c1HDlZEdcN+vrdkdz1Q8dFoJugDQQbEeg+w6RJ6PUFTUge4isCB/ETgYP4icDBVD8ZMndzXLe+8RTOW72jJDymy6Tl7HH/XbMnPO7OV9axx23cG+nXrlN34FRlpGWdTpu1ov2R3PXvTpSzx1FM9RUuJmkDwUYEus8waRJ6fUETkof4isBB/ETgIH4icDDVT8ag3uQ6t75dJi3XFuif7jsaHpOZ/wF73FsbisPj7vrPeva4L74+Fh737Ac72ONwlfoFm79mj8O560dOVrDHUUz1FS4maQPBRgS6zzBpEnp9QROSh/iKwEH8ROAgfiJwMNVP8lFvcp1b3x6oPRuXrd8cD4/pNnkFe9zCzZHc9QGv8gX6npKT4XHPr+ALdIBIlfq3NxWzxxQfKQuPKy2L/+9sqq9wMUkbCDYi0H2GSZPQ6wuakDzEVwQO4icCB/ETgYOpfjJteaQ3+WGNW98bnvlIW6DvOxwRsN2n8AX6sq8OhcfdM2MDe9yh46fC415cuZM9DiAi0As+3sse8+3x8vC4EglxN0IbCDYi0H2GSZPQ6wuakDzEVwQO4icCB/ETgYOpfvLSh7vCovJoGV+g931+tbZA/+5EeVwCfe3OSO76P17jC/TjpyrD46Z/uIs9DiAi0L86eJw9puKH0+FxpyqrtH4exlRf4WKSNhBsRKD7DJMmodcXNCF5iK8IHMRPBA7iJwIHU/3k9bV7I2HZ3/M/2+0vfawt0MsqfoirivtnxZHc9X++vpE97oeqiGB++SM9gf7t8XIo2l+qNQbADqvf+e0J7XEYU32Fi0naQLARge4zTJqEXl/QhOQhviJwED8ROIifCBxM9RNcgO34Kf5nG/Dqem2Bfvp0pPjaNWOXsMdtPxTJXb+/YBN7HABAs5yFEAzNh/+s2q01zk1M9RUuJmkDwUYEus8waRJ6fUETkof4isBB/ETgIH4icDDVT9797EBY/J4s/4E97v6CTdoCHSASOt565GL2mP1Hvw+Pe3CmnkBv+fj7EAzNhxmrd2uNcxNTfYWLSdpAsBGBniSmTZsGLVq0gCZNmkCTJk2gXbt2sHDhwvDraWlpEAgEHNa3b1/Hexw5cgT69+8PZ599Npx99tnQv39/OHr0qNbnMGkSen1BE5KH+IrAQfxE4CB+InAw1U8Kt3wTV970I2982iCB/sdh77HHHD5ZER73gKZAbzd2CQRD8+G1tXu0xrmJqb7CxSRtINiIQE8S8+bNgwULFsDWrVth69atkJOTA40aNYLPP/8cAGyBPmDAADh48GDYSkuduTRZWVnQvHlzWL16NaxevRqaN28O2dnZWp/DpEno9QVNSB7iKwIH8ROBg/iJwMFUP1m57duw+C3/gS/Qh8zd3CCBfuFjC9hjTlVWxVXFHQAgPW+5djV2tzHVV7iYpA0EGxHoLvKLX/wCpk+fDgC2QH/wwQdj/tsvvvgCAoEArF27Nvz/1qxZA4FAAL766iv2zzRpEnp9QROSh/iKwEH8ROAgfiJwMNVP1u0+HBa/lVWn2eNGvrulQQJdZ1x1dSR3/Y6XP9b6eT2fsPu1z1onAj1ZmKQNBBsR6C5QVVUFM2fOhMaNG8OWLVsAwBbo5513Hpx77rlw2WWXwcMPPwzHj0daRbz00kvQtGnTWu/VtGlTePnll9k/26RJ6PUFTUge4isCB/ETgYP4icDBVD/BFdKrTlezx01478ukCXQ87tbn12iNu3naKgiG5sPs9fu0xrmJqb7CxSRtINiIQE8imzdvhp///Odw5plnQtOmTWHBgki40AsvvACFhYVQVFQEM2fOhAsuuAAyMzPDr48ZMwaaNWtW6z2bNWsGY8eOjfkzy8vL4dixY2ErLi6GQCAAJSUlUFlZ6aqVlZWBZVlQVlbm+mcRM9vEV8Q4Jn4ixjHxEzGOmeonuw4di4S4l1ewx722OtI/XefnYYEez7jrn/5Qa9ztL62FYGg+vLV+r+vftdd9hWslJSUi0A1DBHoSqaiogO3bt8P69eth8ODBcN5554Vv0CkbNmyAQCAAGzfa/SPHjBkDF198ca1/d9FFF8G4ceNi/szc3NxaxecCgQAUFBSAZVliYmJiYmJiYmIesvuefgf+99l3tMbMmWvBX6fMgxEv6Y3DAj2ece1HvKs1Ln+GBbfmz4OCt9z/nv1iBQUFItANQwS6i2RkZMDAgQOjvlZdXQ2NGjWCWbNmAUD8Ie5ygy6WCia+IsYx8RMxjomfiHFM/MS2ht6gp+ctd/13SLR53VfkBt08RKC7SJcuXeCOO+6I+lpRUREEAgFYsWIFAESKxH38caTYxtq1a6VInOALxFcEDuInAgfxE4GD+InNhY8taFAOevtxSxP0yczB675ikjYQbESgJ4nHHnsMVq5cCbt374bNmzdDTk4OnHHGGbB48WLYsWMHjBgxAtavXw+7d++GBQsWwKWXXgqtW7eGqqpIC42srCxo2bIlrFmzBtasWQMtWrSQNmuCLxBfETiInwgcxE8EDuInNpcNe69BAr3NqMIEfTJz8LqvmKQNBBsR6EnizjvvhGAwCI0bN4Zf/vKXkJGRAYsXLwYAgH379kGnTp3gnHPOgcaNG8Mf/vAHeOCBB+Dw4cOO9zh8+DD069cPmjRpAk2aNIF+/frB0aNHtT6HSZPQ6wuakDzEVwQO4icCB/ETgYP4iU3rkYsbJNCbD1+UoE9mDl73FZO0gWAjAt1nmDQJvb6gCclDfEXgIH4icBA/ETiIn9hcM3ZJgwR6s5yFCfpk5uB1XzFJGwg2ItB9hkmT0OsLmpA8xFcEDuInAgfxE4GD+IlN57zlSe2f7kW87ismaQPBRgS6zzBpEnp9QROSh/iKwEH8ROAgfiJwED+xyZq6UgR6PXjdV0zSBoKNCHSfYdIk9PqCJiQP8RWBg/iJwEH8ROAgfmKzce8R+MNjC2Da8h1a4+Zu2g8XPrYA3iv6OkGfzBy87ismaQPBRgS6zzBpEnp9QROSh/iKwEH8ROAgfiJwED+JUFl1OqnjvIbXfcUkbSDYiED3GSZNQq8vaELyEF8ROIifCBzETwQO4icCF6/7iknaQLARge4zTJqEXl/QhOQhviJwED8ROIifCBzETwQuXvcVk7SBYCMC3WeYNAm9vqAJyUN8ReAgfiJwED8ROIifCFy87ismaQPBRgS6zzBpEnp9QROSh/iKwEH8ROAgfiJwED8RuHjdV0zSBoKNCHSfYdIk9PqCJiQP8RWBg/iJwEH8ROAgfiJw8bqvmKQNBBsR6D6jtLQUAoEAFBcXw7Fjx1y1kpISKCgogJKSEtc/i5jZJr4ixjHxEzGOiZ+IcUz8RIxrXveV4uJiCAQCUFpa6rZMEWoQge4z1CQUExMTExMTExMTExMLBOzLO8EMRKD7jNOnT0NxcTGUlpYac2Jnwm2+mNkmviLGMfETMY6Jn4hxTPxEjGte95XS0lIoLi6G06f90bfeC4hAF1zj2DHJeRF4iK8IHMRPBA7iJwIH8ROBi/iK8GMjAl1wDVnQBC7iKwIH8ROBg/iJwEH8ROAiviL82IhAF1xDFjSBi/iKwEH8ROAgfiJwED8RuIivCD82ItAF1ygvL4fc3FwoLy93+6MIhiO+InAQPxE4iJ8IHMRPBC7iK8KPjQh0QRAEQRAEQRAEQTAAEeiCIAiCIAiCIAiCYAAi0AVBEARBEARBEATBAESgC4IgCIIgCIIgCIIBiEAXBEEQBEEQBEEQBAMQgS4IgiAIgiAIgiAIBiACXRAEQRAEQRAEQRAMQAS6IAiCIAiCIAiCIBiACHRBEARBEARBEARBMAAR6IIgCIIgCIIgCIJgACLQBUEQBEEQBEEQBMEARKALgiAIgiAIgiAIggGIQBcEQRAEQRAEQRAEAxCBLgiCIAiCIAiCIAgGIAJdEARBEARBEARBEAxABLogCIIgCIIgCIIgGIAIdEEQBEEQBEEQBEEwABHogiAIgiAIgiAIgmAAItAFQRAEQRAEQRAEwQBEoAuCIAiCIAiCIAiCAYhAFwRBEARBEARBEAQDEIEuCIIgCIIgCIIgCAYgAl0QBEEQBEEQBEEQDEAEuiAIgiAIgiAIgiAYgAh0QRAEQRAEQRAEQTAAEehJIjc3FwKBgMN+9atfhV+vrq6G3Nxc+M1vfgM//elPIS0tDT7//HPHexw5cgT69+8PZ599Npx99tnQv39/OHr0aLJ/FUEQBEEQBEEQBCEBiEBPErm5uXD55ZfDwYMHw/btt9+GXx8/fjw0adIE5syZA0VFRdC3b1/4zW9+A8ePHw//m6ysLGjevDmsXr0aVq9eDc2bN4fs7Gw3fh1BEARBEARBEAThR0YEepLIzc2FVq1aRX2turoafv3rX8P48ePD/6+8vByaNm0Kzz33HAAAfPHFFxAIBGDt2rXhf7NmzRoIBALw1VdfJfbDC4IgCIIgCIIgCAlHBHqSyM3NhbPOOgt+85vfwAUXXAB9+/aFnTt3AgDAzp07IRAIwKZNmxxjevfuDbfffjsAALz00kvQtGnTWu/btGlTePnll2P+3PLycjh27FjYjh49Cjt37oTS0lLH/xcTExMTExMTExMT85eVlpZCcXExnD59+kdUPkJDEIGeJBYuXAhvvfUWbN68GQoLCyEtLQ1+9atfQUlJCaxatQoCgQAcOHDAMWbAgAHQrVs3AAAYM2YMNGvWrNb7NmvWDMaOHRvz50bLfRcTExMTExMTExMTE1NWXFz844ofIW5EoLvEyZMn4Ve/+hXk5+eHBfrXX3/t+Dd33303dO/eHQBsgX7xxRfXep+LLroIxo0bF/Pn0Bv0ffv2QSAQgN27d0NJSYmrdvDgQSgoKICDBw+6/lm49qcHxokl2Fo+XNvaPDoeCgoKoM2j46O+Lsa35o+mrrUJ1fhJaLyrn6OFWMItFfzEaPu3WJvBNX4yeHxC3t/t/YzYj2de3M9i2717NwQCASgtLf1xxY4QNyLQXSQzMxPuvffehIa4U44dOwaBQACOHTvWsA//I1BZWQmWZUFlZaXbH4VN8/+dLJZguyxU21rnTAHLsqB1zpSor4vx7dKc1LVWQ20/aTV0iquf44+PiSXaUsFPjLYhYq2G1fjJsCkJeX8hdfDifhZjkjYQbESgu0R5eTn89re/hREjRoSLxE2YMCH8ekVFRdQicR9//HH436xduxYCAb0icSZNQi8uaB2zJ4gl2NK7jK1l3bPGg2VZ0D1rfNTXxfjWrcXQlLXrrhwOlmXBdVcOd/VzdL16hFiC7Zo+eXFb2m35YFkWpN2W36D3SWXLbDvC99aj4yiwLAt6dByVkPcXUgcv7mcxJmkDwUYEepJ4+OGH4YMPPoBdu3bB2rVrITs7G5o0aQJ79uwBALvNWtOmTeHtt9+GoqIiuO2226K2WWvZsiWsWbMG1qxZAy1atNBus2bSJPTigtbhholiCbYuncbUsqzMcWBZFmRljov6uhjful71eMpazw4jwbIs6NlhpKufo8ONE8USbA05BMy4MQ8sy4KMG/NcP5A01a7uN8n3du0d9kHOtXfkJ+T9hdTBi/tZjEnaQLARgZ4kVF/zRo0awfnnnw833XQTbNmyJfx6dXU15Obmwq9//Wv4yU9+Ap06dYKioiLHexw+fBj69esHTZo0gSZNmkC/fv3g6NGjWp/DpEnoxQWt65W5Ygm2a3tNrGVdbpoElmVBl5smRX1djG9Zv//flLVelz4KlmVBr0sfdfVztL85TyzRdlP81rmvLbw6981v0Puksl3110m+tw5/t/2kw9/zE/L+Qurgxf0sxiRtINiIQPcZJk1CLy5obotXP5gIdBHoItDFRKC7a26LYxNMBLrAxYv7WYxJ2kCwEYHuM0yahF5c0LL+74NiCTYR6Im1jA6jUtay0sfYqRDpY1z9HJ0zxokl2ESgJ9Y69pzge8u4viYV4vrEfB9C6uDF/SzGJG0g2IhA9xkmTUIvLmhu5w/7wTplja9lmb0mgmVZkNlrYtTXxfjmdu5wIi39FvsgJ/2WSa5+ji6dx4gl2NK6j4/bumbb60nX7IkNep9Utra3TvK9dexvH+R07J+fkPcXUgcv7mcxJmkDwUYEus8waRJ6cUHr1GOCWIIt49rRtSyry1j7ZrTL2Kivi/HN7Rv8RJopkRZuiys/WEPWmMze9s1oZu8819c7U81tcWyCiUAXuHhxP4sxSRsINiLQfYZJk9CLC5rbmyY/mAh0Eegi0MVEoLtrbotjE0wEusDFi/tZjEnaQLARge4zTJqEXlzQ3O5h7QfreN2EWpZxQ00u4A15UV8X41v3S0Ipa9ktc8CyLMhumePq50jrOk4swZYKqRAmm9uHbSZYog/8hNTBi/tZjEnaQLARge4zTJqEXlzQXK9c7APL+sMjtazXZSG7Ovdloaivi/Gt69UjUtZ6XjvK7oN+7ShXP8c1ffLEEmwmF/9KBXO7VoYJlujaJ0Lq4MX9LMYkbSDYiED3GSZNQi8uaG6LVz+YCHQR6CLQxUSgi0B320SgC1y8uJ/FmKQNBBsR6D7DpEnoxQXN7Zw4P1i0zXjabXYuYNpt+a4LA6+b263Q/NBmze055AdrSKeIrMxxtp9kjnO9a4WplnnNSN9bj7TRYFkW9EgbnZD3F1IHL+5nMSZpA8FGBLrPMGkSenFBc/t22Q/mxk2Gn8ztHPhEmim1CtzuYe0HE4GeWOvWaqjv7bqrh4NlWXDd1cMT8v5C6uDF/SzGJG0g2IhA9xkmTUIvLmhZv3tALMEmIamJtav/Mill7drb7UiLa2/Pd/VzuC1e/WBdOo6O27IyarpCZIxt0PuksrldLNQE6541HizLgu5Z4xPy/kLq4MX9LMYkbSDYiED3GSZNQi8uaG6LVz+YCHQR6CLQxUSgi0B320SgC1y8uJ/FmKQNBBsR6D7DpEnoxQWtXd9JYi5Yp3628OrUL9/1z+J1u/KO/JS19ndNBsuyoP1dk139HNf2niiWYBOBnlhz++9rgnW5uabN2s2TEvL+Qurgxf0sxiRtINiIQPcZJk1CLy5obt8Q+sE6Z4yrZd2yJoBlWdAta0LU18X45nZ/5USaKf2tu//yHrEEW0N6qHftaa8nXXtOcL2fu6nmdg9yE0z6oAtcvLifxZikDQQbEeg+w6RJ6MUFze0K3H4wEehi8ZoxfpIplmjLuuChuK3XJY/YbRsveaRB75PK5vYBgQmW6IMcIXXw4n4WY5I2EGxEoPsMkyahFxc0t8WrH8xo4SVmtBnjJwYI2FQ3Eegi0EWgC6bgxf0sxiRtINiIQPcZJk1CLy5obucP+8Ey2o+qZVmda/pbdx4T9XUxvrndCs0PbdbcDs31g3VvPiRuy24zDCzLguw2wxr0PqlsXa963PfWs8NIsCwLenYYmZD3F1IHL+5nMSZpA8FGBLrPMGkSenFBczvH1g+Wce3oWpbVpaaoU5exUV8X41v3Zo+mrGU3H2wLr+aDXf0c1/w5TyzB1jF7QtyWcWPNQc6NDXufVDa3D2BMMMlBF7h4cT+LMUkbCDYi0H2GSZPQiwua2xsGP5jRocspYG4fECTSTDnIcbv6tB+s7W2T4raOf7W7QnT8a36D3ieVze1IKhMs0d1DhNTBi/tZjEnaQLARge4zTJqEXlzQ3BavfjAR6CLQRaCLiUAXge62iUAXuHhxP4sxSRsINiLQfYZJk9CLC1pa9/FiCTYR6Ik1t/++ibSu2RPtok7ZE139HJ2yxBJtHW6YGLel96lpx9dnUoPeJ5XtyjvyfW/t75oMlmVB+7smJ+T9hdTBi/tZjEnaQLARge4zTJqEXlzQ2t+cJ5Zgi3Zb1uXmmlzAmye5fnPndXNbRPtBoHfpNEYswdbulry4rdNfam5G/5LfoPdJZWt76yTfW8f+NZEW/fMT8v5C6uDF/SzGJG0g2IhA9xkmTUIvLmht/pYvlmDr1GNCLcvsbRd1yuydF/V1Mb65XXwqkWZM8S8DKtqLxTZTqv2bbFnnD/K99brwQbsd34UPJuT9hdTBi/tZjEnaQLARge4zTJqEXlzQ3BavfjAR6CLQRaCLJdJEoNdvbotjE0wEusDFi/tZjEnaQLARge4SY8eOhUAgAA8++GD4/5WXl8OgQYPg3HPPhbPOOgt69eoFxcXFjnF79+6F7OxsOOuss+Dcc8+F+++/HyoqKtg/16RJ6MUF7Yq78sUSbN3+NKyWXdc2FyzLguva5kZ9XYxvXa/MTVnr2X6E3be4/QhXP0fmNSPFEmwNmQOyntRvbrdMNMES3bZRSB28uJ/FmKQNBBsR6C6wbt06uOCCC6Bly5YOgX7vvffCb3/7WygsLIRNmzZBeno6tGrVCqqqqgAAoKqqCpo3bw7p6emwadMmKCwshPPPPx8GDeKfxJo0Cb24oF1xZ75Ygs3om9EUMLeLeyXSMnvZOeiZvSa6+jk6Z44TS7DJDXpirfvlOb637CuG2gL9iqEJeX8hdfDifhZjkjYQbESgJ5kTJ05As2bNoLCwENLS0sICvbS0FBo1agSzZs0K/9sDBw7AGWecAYsWLQIAgIULF8IZZ5wBBw4cCP+bmTNnwk9+8hP2pDJpEnpxQXNbvPrBRKAn1twW0SLQxUSgm29ui2MTTAS6wMWL+1mMSdpAsBGBnmRuv/12+Ne//gUA4BDoS5cuhUAgAEeOHHH8+5YtW8Lw4cMBAGDYsGHQsmVLx+tHjhyBQCAAy5YtY/18kyahFxe0Pz42WSzBdtVfJ9WyDn+3q+l2+Ht+1NfF+HbNn/NS1tJus/0k7bZ81z+LmLkmflK/ud3izASTNmsCFy/uZzEmaQPBRgR6Epk5cyY0b94cTp06BQBOgf76669D48aNa43p2rUrDBw4EAAABgwYAF27dq31bxo3bgwFBQVRf2Z5eTkcO3YsbMXFxRAIBKCkpAQqKytdtbKyMrAsC8rKylz/LFxrPmayWIKtxYgptezKUVPBsiy4ctTUqK+Ladio1LUrx9T4yZiprn6O5qPFEm2p4Ccmm9vPAROszbgpYFkWtBmXmO/D7f2M2I9nXtzPYispKRGBbhgi0JPEvn374H/+53/g008/Df8/jkDPzMyEe+65BwBsgd6tW7da/6ZRo0Ywc+bMqD83NzcXAoFALSsoKADLssTExMTExMTExMTEfGoFBQUi0A1DBHqSmDt3LgQCATjzzDPDFggE4P/8n/8DZ555JixZsiQhIe5yg/7j2hX/niKWYJMbrwTfjBlw+5koazPW9pM2Y6e6+jkuHzdZLNE2Nn67Yrx9M3rF+CkNep9UtssmiLXOs/2kdd6UhLy/2/sZsR/PvLifxSY36OYhAj1JHD9+HIqKihx25ZVXQv/+/aGoqChcJG727NnhMV9//XXUInFff/11+N/MmjVLisQlkcsfmSyWYGt9d34ta3uvnQvY9t7or4vx7crbU9fa31mTM3rnZFc/x5/uFUu43RO/tf1nzXryz8kNep9Utlb3iV19v+0nV98/OSHvL6QOXtzPYkzSBoKNCHQXwSHuAHabtd/97newZMkS2LRpE3Tp0iVqm7WMjAzYtGkTLFmyBH73u99Jm7Uk4vqm1AfmRjVdP1mHGyamrKX3mQSWZUF6n0mufo4uHUeLJdg69ZgQt2X2tqu4Z/bOa9D7pLJlXfCQ763XJY+AZVnQ65JHEvL+Qurgxf0sxiRtINiIQHcRKtBPnToFgwYNgnPOOQd+9rOfQXZ2Nuzbt88xZu/evXDdddfBz372MzjnnHNg0KBBUF5ezv6ZJk1CLy5oblfg9oNJm7XE2jV98lLWHNW5Xfwc6eljxRJsXTqNiduyMseBZVmQlTmuQe+Tytbt/7vD93bdL+8Cy7Lgul/elZD3F1IHL+5nMSZpA8FGBLrPMGkSenFBc1u8+sFEoItAF4EuJgJdBLrbJgJd4OLF/SzGJG0g2IhA9xkmTUIvLmhui1c/WMeeE2pZxvU1Av36vKivi/Gt/U15KWud+9oCvXPffFc/h9uHMH6w7peE4rbsljl2ykzLnAa9TypbZtsRvrceHUeBZVnQo+OohLy/kDp4cT+LMUkbCDYi0H2GSZPQiwva1f0miSXYujcfUsuy2wyzN9RthkV9XYxvnTPHpax16zEBLMuCbj0muPo5Ol43QSzBlnnNyLitR9poW3iljW7Q+6SydT9voO8t+3f32c+d392XkPcXUgcv7mcxJmkDwUYEus8waRJ6cUG7+i+TxBJsGe1H1bKszmPskNTOY6K+LsY3t0OTE2ndu48Hy7Kge/fxrn6OjGtHiyXY0rqPj9u6Zk8Ey7Kga/bEBr1PKpvbRQBNsKyMsfZzJ2NsQt5fSB28uJ/FmKQNBBsR6D7DpEnoxQXNbfHqBxOBLgJdBLqYCHQR6G6bCHSBixf3sxiTtIFgIwLdZ5g0Cb24oLW9dZJYgq1L5zG1LKtbTVGnbuOivi7Gt+6XDk5Zy241xA5JbYbXVIEAACAASURBVDXE1c/hdu6sHywVahWYbG6LYxNMBLrAxYv7WYxJ2kCwEYHuM0yahF5c0Ny+XfaDZf3hkVrW67KQ3Y/2slDU18U07MKHU9Z6/fHftp/88d/ufpb/+6BYgq1T1vi4LbOXfYOe2Wtig94nlc3tGgMmWMYNNcVJb8hLyPsLqYMX97MYk7SBYCMC3WeYNAm9uKC5LV79YBkdRtWyrPSaEPf0MVFfF+Ob27fcfrhBT+s6TizBZnJ17lSwDjdO9L2l3zIJLMuC9FsmJeT9hdTBi/tZjEnaQLARge4zTJqEXlzQ3BavfjAR6CLQRaCLiUAXge62iUAXuHhxP4sxSRsINiLQfYZJk9CLC5rb+dl+MAlJTaxlXfBQylqvSx6xQ9wvecTVz3Ft74liCbaG1GGQmhb1W4cbJvre0vvUCPQ+kxLy/kLq4MX9LMYkbSDYiED3GSZNQi8uaG3+li+WYIsm2jv2t4s6dewf/XUxvrm96fXyhlrMHGvXd1Lc1qmfvZ506pffoPdJZXP79toEkxt0gYsX97MYk7SBYCMC3WeYNAm9uKC5LV79YCLQRaDHayLQ/WMi0EWgi0AXTMGL+1mMSdpAsBGB7jNMmoReXNDa35wnlmBr+c/JteyqB6aAZVlw1QNTor4uJtbyn+b4SesB+WIJtjZ/j9+uGTAZLMuCawZMbtD7pLQZcFjrtl1zd42f3D05Ie8vpA5e3M9iTNIGgo0IdJ9h0iT04oLW7pY8sQRb64H5taztffZGqe19k6O+LsY3t0W0HwT6FXfmiyXYWt8dv7W9t2Y9uXdyg94nlc3tSB8TLNGRW0Lq4MX9LMYkbSDYiED3GSZNQi8uaG1vmySWYItWsblrzwlgWRZ07TnB9erRXrcrb89PWWt/py282t852dXPcU2fPLEE29X9JsVt195hC69r78hv0PuksrldpM4ES3QxQSF18OJ+FmOSNhBsRKD7DJMmoRcXNLfFqx9MBLoIdBHoYiLQRaC7bSLQBS5e3M9iTNIGgo0IdJ9h0iT04oLW7U/DxBJsHa+bUMsybsgDy7Ig44a8qK+L8a39TXkpa5372sKrc998Vz/H1X+ZJJZg69JpTNyWlVkjvDLHNeh9Utm6N3vU95bdfDBYlgXZzQcn5P2F1MGL+1mMSdpAsBGB7jNMmoReXNDc7v3rBzNZeKWCub3xT6SZIrzcrsDtB2vIHJD1pH5LTx/re+vefTxYlgXdu49PyPsLqYMX97MYk7SBYCMC3WeYNAm9uKC5fWvkB5MNdWIt6zf/TFnr9fsHwLIs6PX7B1z9HJ2yxosl2BrSKaLzrTXrya35rnetMNXcjqQywa5rmwuWZcF1bXMT8v5C6uDF/SzGJG0g2IhA9xkmTUIvLmhui1c/mAj0xJrbIloEupgIdPPNbXFsgolAF7h4cT+LMUkbCDYi0H2GSZPQiwtahxsmiiXYMtqPqmVZncfYocudx0R9XYxv3S8dnLKW3WqInTPaaoirnyO9y1ixBFsqpEKYbG4XqTPBEl1MUEgdvLifxZikDQQbEeg+w6RJ6MUFze38bD+YG9V0/WQZHUalrGWl1xzkpLv7e3a4caJYgq0hhRKl6GT95vZzwATrcvMksCwLutw8KSHvL6QOXtzPYkzSBoKNCHSfYdIk9OKC1rHnBLEEW+eMcbWsW5bdZq1bVvTXxfjm9t83kZZxfY3wuj7P9c8illgzWXilgnW/PMf3ln3FUDsi54qhCXl/IXXw4n4WY5I2EGxEoPsMkyahFxc0tzelfjAR6CLQ4zUR6P4xEegi0EWgC6bgxf0sxiRtINiIQPcZJk1CLy5obod1+sG6/88/aln2/xtkb5T+36Cor4vxze0DgkSaKQc5budn+8HSuo6L27r2tP2ka88JDXqfVLbMa0b63nqkjQbLsqBH2uiEvL+QOnhxP4sxSRsINiLQfYZJk9CLC9pVf50klmDrnDmulnXrUSO8ekyI+roY39ze+CfSTBFeXa96XCzBltl2RNzWo+MoW3h1HNWg9xFLbUu0nwipgxf3sxiTtIFgIwI9SUybNg1atGgBTZo0gSZNmkC7du1g4cKF4dfLy8th0KBBcO6558JZZ50FvXr1guLiYsd77N27F7Kzs+Gss86Cc889F+6//36oqKjQ+hwmTUIvLmitB+SLJdg6Zk+oZRk31oQu35gX9XUxvqV1H5+y1jV7oi3Qsye6+jncvl32gzVE3PfsMBIsy4KeHUa6ftBgqrkdYm+CSZE4gYsX97MYk7SBYCMCPUnMmzcPFixYAFu3boWtW7dCTk4ONGrUCD7//HMAALj33nvht7/9LRQWFsKmTZsgPT0dWrVqBVVVVQAAUFVVBc2bN4f09HTYtGkTFBYWwvnnnw+DBg3S+hwmTUIvLmhui1c/mAh0Eegi0MVEoItAd9tEoAtcvLifxZikDQQbEegu8otf/AKmT58OpaWl0KhRI5g1a1b4tQMHDsAZZ5wBixYtAgCAhQsXwhlnnAEHDhwI/5uZM2fCT37yE60JZdIk9OKC1vrufLEE2xV31rZ2AyeDZVnQbuDkqK+L8c3tv28ire29tp+0vXeyu5/FgIOuVLeW/5wct131wBSwLAuuemBKg94nle2Ku/J9b+3uqXnu3JOY70NIHby4n8WYpA0EGxHoLlBVVQUzZ86Exo0bw5YtW2Dp0qUQCATgyJEjjn/XsmVLGD58OAAADBs2DFq2bOl4/ciRIxAIBGDZsmUxf1Z5eTkcO3YsbMXFxRAIBKCkpAQqKytdtbKyMrAsC8rKylz/LFxrNXSKmAt29fCpYFkWXD18quufRcxcM8VPWuaKJdpajIzfrhxt+8mVo6c26H1S2kaIXTmqxk9GTU3I+7u9nxH78cyL+1lsJSUlItANQwR6Etm8eTP8/Oc/hzPPPBOaNm0KCxYsAACA119/HRo3blzr33ft2hUGDhwIAAADBgyArl271vo3jRs3hoKCgpg/Mzc3FwKBQC0rKCgAy7LExMTExMTExMTExHxqBQUFItANQwR6EqmoqIDt27fD+vXrYfDgwXDeeefBli1bYgr0zMxMuOeeewDAFujdunWr9W8aNWoEM2fOjPkz5Qb9xzW3bwj9YG0erW3XDJ4KlmXBNYOnRn1dTKzNo+b4SescsUTbn4bGb21rIi3aDp/aoPdJaRsi1nZYjZ8Mm5qQ93d7PyP245kX97PY5AbdPESgu0hGRgYMHDgwoSHuFJPyTCorvZez0+Zv+WIJti4dR9eyrIyxYFkWZGWMjfq6GN/a35SXsta57//f3rlHR1Wd/X8Uk4AIsbi0oCAIEpJyUSImQO4zSWaSTLjKTW7eKBdTRF/rC0oJl9znAm/fUttS6mK1BFwVPGu1ZbVKq1gBXe0CKy60F+VW4F0tFdRSAkWe3x97zO+MM9aTGfbs2/ez1uefcyabDey983znnLNPiCzLotIZIaH9EL25lQkWVbcmrGdiZNPJiYGk2tFZ0a9MlEHer20E+qBiPWtHpmwAGAjoAnG73TR//vzOTeKef/75znOnTp2Ku0ncqVOnOj+zfft2bBKXYkQXpSbozXoqRv/IFWRZFvlHroh7Hjo3f2ZQW4vmsIBeNCcktB+idzg3QXdpY8L6KpvZF36VzUm1o7PFVa3GWz6BfZFTPiHApX2gDyrWs3ZkygaAgYCeIlasWEGvvfYaHTlyhN5++216+umn6dprr6WXXnqJiNhr1vr370+7d++mAwcOkNvtjvuaNY/HQwcOHKDdu3dT//798Zq1FCM6vJogAjoCOgI6REBHQBctAjpwior1rB2ZsgFgIKCniIceeogGDhxI6enpdPPNN5PH4+kM50REFy5coLq6OurTpw/16NGD/H4/HT9+PKqNY8eOUU1NDfXo0YP69OlDdXV11NHR0aV+yDQJVVzQRN+ebIK+QY/HWDvsSbIsi2qHPRn3PHSu6NvQTbjFXXR4NcGimtaE9UyK3OI+KZBUOzpb4m0x3gp/G7vF3d/GpX2gDyrWs3ZkygaAgYBuGDJNQhUXtFJPM+RsvGLc62shy7LI62sRHgxUt8jfqq2eyZHgNTkgtB/u4kbI2WJfS8KW17LgVV7bllQ7Oiv6TioZdE8NkmVZ5J4a5NI+0AcV61k7MmUDwEBANwyZJqGKC5rocGWCBZPbYiybzgqlsunBuOehcz3j12mrr7SR3bpc2ii0H6I3+DJB3OLO19LyZuOtrGKbxFVWtXJpH+iDivWsHZmyAWAgoBuGTJNQxQVNdHg1QQR0BHQEdIiAjoAuWgR04BQV61k7MmUDwEBANwyZJqGKC5ro176YIAI6X8vKmrTV6408CuFtEdoP0c/OmqCnsCFhfe7IaxvdTUm1o7Pl+WuMt6poHVmWRVVF67i0D/RBxXrWjkzZADAQ0A1Dpkmo4oImumgywcrRq2KsyV9NlmVRTf7quOehc8uvuU9bq66fxQrq62cJ7YfoOWSCyexzUemLXBn1tQrfc0NWRT//LYN4Bh04RcV61o5M2QAwENANQ6ZJqOKCJnqHcxPELu58HXdfQFtLZrFd3EtmhYT2w1OwDnI2mbt0KqpZQK+obhV+x5CsjpsWMN6o9YRD+0AfVKxn7ciUDQADAd0wZJqEKi5oosOrCSKgI6AjoEMEdAR00SKgA6eoWM/akSkbAAYCumHINAlVXNDyZwUhZ0U8C2iSootelQtqp4p+3ZwJ6rBXgcyK/rJNBnl/4Qf0QcV61o5M2QAwENANQ6ZJqOKCJjqAmKD3lsUx+m+vI8uyyH97Xdzz0Lmir3zy1FcW2cW9rFFoP0SHVxP0Dn86Yf25K9l6krsyqXZ0tmBSm/GWTYtsTjotyKV9oA8q1rN2ZMoGgIGAbhgyTUIVFzTRtx2a4PipgRhLZ7IrGaUzQ3HPQ+cW1bRqq2dSgCzLIs8ksX/P/JlByNlk5gDWEwdOgaUzIuNkRohL+0AfVKxn7ciUDQADAd0wZJqEKi5oosOrCaKg5qvoEI2ADhHQFVCCgCxaBHTgFBXrWTsyZQPAQEA3DJkmoYoLmujbv01w9NdDMeYvCZNlWZS/JBz3PHTuPQ/o67hH2DgZ90hYaD9yH4K8HTM/ccc/zMbJ+IfDSbWjs6MfgfmLIr93FoW5tA/0QcV61o5M2QAwENANQ6ZJqOKC5s16CnI23sZxRXPZlYyiuSHhm9hBeZVlnNw7B/J27PRAwhbfz8ZJ8f2hpNrRWdFzWQZ5rydAH1SsZ+3IlA0AAwHdMGSahCouaKLDqwnKHLyg3MoyTkSHVxNEQEdAV309AfqgYj1rR6ZsABgI6IYh0yRUcUErmNwGOesubYzRV9nMdueubI57Hjq3zN2krV5f5PVZvhah/RC9+7QRJrHGlE2P7M49PSh8vZNV0c9/yyCeQQdOUbGetSNTNgAMBHTDkGkSqrigCd+4xwBl3vxLB0s9zdpa6Wsly7Ko0if271k4oQ3ytjZx3VNYQHdPCSbVjs6K3otEBqPeg86hfaAPKtazdmTKBoCBgG4YMk1CFRc00Vc1TLB83NoYq0oayLIsqippiHseOlf0/y9PZbkyOu6+AORsMm+KqKhmX+RUVLcKf2uFrIq+vVwGcYs7cIqK9awdmbIBYCCgG4ZMk1DFBU10ADFBBHQE9ERFQDdHBHQEdAR0IAsq1rN2ZMoGgIGAbhgyTUIVF7SxM4KQsxV5a2KsLlxHlmVRdeG6uOehc0U/A89TWfYqEH17sgnq8EWOzIp+1EkGS2dGnkGfGeLSPtAHFetZOzJlA8BAQDcMmSahigua6J11TbCsrClGrzey+Ze3Je556FzRV+Z4KsuVUdGb5Zmgu7gxYX3lkS9yypuTakdni30txlte20aWZVF5bRuX9oE+qFjP2pEpGwAGArphyDQJVVzQiqpbIWfdRQ0x+jxNrKD2NMU9D50r+gsYnsry+qyKMfWQszJfGdVBz/h1xusrbWS/d0obubQP9EHFetaOTNkAMBDQDUOmSajigiY6vJogAjoCOgI6REBHQBctAjpwior1rB2ZsgFgIKAbhkyTUMUFTXTRZIKl5c0xVlZFXp9V1Rr3PHSu6NvQTbjFXXSwMMG8+4MJWziPBfTCeaGk2tFZ0a9MlEHer20E+qBiPWtHpmwAGAjohiHTJFRxQRszLwQ5K+JKhkl6b16orf4Bj5JlWeQf8KjQfoj+osIEZX6/tQ6KvtNHBnnfuQX0QcV61o5M2QAwENBTRFNTE40ZM4ZuuOEGuvnmm2nixIn03nvvRX2mo6OD6urq6KabbqLrr7+eamtr6cSJE1GfOXbsGPn9frr++uvppptuom984xt08eJFx/2QaRKquKDd80AIcha7uPPV22eBtvpvXcwC+q2LhfZD9G72Jlg4oS1h3VPZLu7uqcGk2tFZ0a+DlEHer/cE+qBiPWtHpmwAGAjoKcLr9dJzzz1H77zzDr311ltUU1NDt99+O/3zn//s/MyiRYvotttuo5dffpkOHDhAZWVldNddd9Hly5eJiOjy5cs0YsQIKisrowMHDtDLL79Mt956K9XV1Tnuh0yTUMUFTXR4NUEEdAR0BHSIgI6ALloEdOAUFetZOzJlA8BAQBfE3/72N3K5XLRnzx4iIjp37hylpaXR9u3bOz9z8uRJuvbaa+mXv/wlERHt2rWLrr32Wjp58mTnZ7Zt20YZGRmOJ5VMk1DFBS1nRRhyNm92MMbC+ZFnRueH4p6Hzr3nwZC2jlsQJsuyaNyCsNB+iH6HtQmOnxJI2NIZkU3iZoSSagfqLe9xAvRBxXrWjkzZADAQ0AXx5z//mVwuFx06dIiIiH7961+Ty+WiDz/8MOpzo0aNolWrVhER0be+9S0aNWpU1PkPP/yQXC4X/eY3v3H058o0CVVc0AatD0LODg6EYswJseCVEwrHPQ/h4IA842RIK+Tt4CTMCUTGSSCcVDta2wZzgpFxEgxzaR/og4r1rB2ZsgFgIKAL4MqVK1RbW0uFhYWdx7Zu3Urp6ekxn62oqKCvf/3rRES0YMECqqioiPlMeno6tbe3x/2zOjo66KOPPur0xIkT5HK56MyZM3Tp0iWhnj9/nizLovPnzwvvi1NzgmHI2ayNoRhHfpcVSiO/G/887IL/q68jvxMZJ98JC+3HsG9D3mZ9J3FHboyMk43hpNqBest7nIiuZ+DVU8V61u6ZM2cQ0CUDAV0AS5YsoYEDB0ZtAPdFAb28vJwWLlxIRCygV1ZWxnwmLS2Ntm3bFvfPqq+vJ5fLFWN7eztZlgUhhBBCCCE01Pb2dgR0yUBATzF1dXXUv39/+uCDD6KO87rFHVfQr675i8OQsyPXro9xTMMGsiyLxjRsiHseOveulfqat4qNk7xVG4T3BfJ1VH3i3ruGjZN712xIqh2dFb1OySDv3zui6xl49VSxnrWLK+jygYCeIq5cuUKPPvoo3XrrrfSnP/0p5vxnm8Q9//zzncdOnToVd5O4U6dOdX5m+/bt2CQuhXztqTDkbMWY+hirx68hy7KoevyauOehcwtr27TVPSWyO/eUoNB+jJ0RhJzVYZzIrKdgnfH6yhrJsizylTVyaR/og4r1rB2ZsgFgIKCniMWLF1NmZia9+uqrdPr06U7/9a9/dX5m0aJF1L9/f9q9ezcdOHCA3G533NeseTweOnDgAO3evZv69++P16ylENHh1QQR0BHQVQ9eosOrCeowTmRWdDiWQQR04BQV61k7MmUDwEBATxHxngN3uVz03HPPdX7mwoULVFdXR3369KEePXqQ3++n48ePR7Vz7NgxqqmpoR49elCfPn2orq6OOjo6HPdDpkmo4oJ215IQ5GyppznGSl8rWZZFlb7WuOehc71feVhb/f0WkmVZ5O+3UGg/ivytkLMVaTMTtrr3HPaFX+85SbWjs+OnBoy3dGbkNWszQ1zaB/qgYj1rR6ZsABgI6IYh0yRUcUG7e2EIchZXvDhfGSts0Fafu4ld8XI3ie3H7csgZz3j1yWsrzRyZbS0Mal2dLaoptV4PZMCZFkWeSYFuLQP9EHFetaOTNkAMBDQDUOmSajignb3ohDkbP6sYIxFc9mVjKK58c9D54ou/HkqS/AqczdBzrqLGhLW54l8keNJrh2dLfa1GG95bRtZlkXltW1c2gf6oGI9a0embAAYCOiGIdMkVHFBEx1eTRABHQEdAR0ioCOgixYBHThFxXrWjkzZADAQ0A1Dpkmo4oI2+ushyNkSb0uMFX5WKFX42+Keh84V/Vynys+MOrWsrAnyNolw7/W1kGVZ5PW1CP+iQVZF314ug7jFHThFxXrWjkzZADAQ0A1Dpkmo4oKWNzsIORtvQyjP5EihNDkgfHMq1b13TlBbCx5gAb3ggZDQfogOFiY47r5AwpbMYuOkZFYoqXZ01nfHE8Zbm/1NsiyLarO/yaV9oA8q1rN2ZMoGgIGAbhgyTUIVF7T8mUHI2fFTAjGWzohcGZ0RinseOlf0FwQ8leWLHNFXP00wmcc88MjMlyv6bRMyyPvtIUAfVKxn7ciUDQADAd0wZJqEKi5oosOrCSKgI6AjoEMEdLGKDscyiIAOnKJiPWtHpmwAGAjohiHTJFRxQRN9C68JFle1xlg+gQWv8gmBuOehcytHr9LWmvzVZFkW1eSvFtoP0a+bM0Ed9iqQWe/wp43Xn7uSLMsif+5KLu0DfVCxnrUjUzYADAR0w5BpEqq4oIkOrybo/crDMfr7LWSFUr+Fcc9D54r+goCnsnyRI/r5bBOsvGtlwtbkrWJf5OStSqodnfX1X2q8tXc+zp5Bv/NxLu0DfVCxnrUjUzYADAR0w5BpEqq4oI1+JAQ5WzGmPsbq8WvIsiyqHr8m7nnoXNG3jap8S6pTRX9RYYJF1YnrmRh5FGJiIKl2dLZgUpvxlk0LkmVZVDYtyKV9oA8q1rN2ZMoGgIGAbhgyTUIVFzTR4dUEEdAR0BHQIQI6ArpoEdCBU1SsZ+3IlA0AAwHdMGSahCouaHcvCkHO4rVIfBW9SR1PZdlM0F3aCDk7Zn4oYcc/HCbLsmj8w+Gk2tFZ0a/blMHC+Ww9KeT07wH0QcV61o5M2QAwENANQ6ZJqOKCds+DIcjZeFfLZHm2WAdF7zHAU1negy76TQgmmPtwKGHHLmQBfezCcFLt6Kzoq9cyiCvowCkq1rN2ZMoGgIGAbhgyTUIVFzTRr74xwcIJbTG6p7JCyT01/nnoXNG7Q/NUlt25Rc8hE0xmDmA9+XIrR6403poxkc0Ex6zi0j7QBxXrWTsyZQPAQEA3DJkmoYoLmuii1ARRUPNVdIhGQIe81gmnYj35ckWHYxlEQAdOUbGetSNTNgAMBHTDkGkSqrig3b0wBDlbWt4cY2VVZPOvqta456Fzy8qatNXrbSHLssjrbRHaj8LaNsjZintXJ2x1wVq26WTB2qTa0VnfoMeNt3bYk+w1a8Oe5NI+0AcV61k7MmUDwEBANwyZJqGKC9rIpWHIWc/4dTH6ShvJsizylTbGPQ+d6/3aCm31j15JlmWRf/RK4X2BfC3ytyasZ3JkF/fJgaTa0Vl3UYPx+jxN7PeOp4lL+0AfVKxn7ciUDQADAd0wZJqEKi5oosOrCSKgI6AnKgK6OSKgI6AjoANZULGetSNTNgAMBHTDkGkSqrigjfpGGHI23u2s7imRZ0anBIXfWqu6vgGPaWvt0CfYLalDnxDaD09hA+RsweS2hC2bHtmde3owqXZ0tqSi2XgrqtmjVRXVrVzaB/qgYj1rR6ZsABgI6IYh0yRUcUEbVReGnC31NMdY6Ys8g+5rjXseOlf0+6t56qtsZle8KsX+PUU/i2+CMgcvHSz2tRhveW0be71nbRuX9oE+qFjP2pEpGwAGArphyDQJVVzQRIdXEyyqbo3RMzFyS+rEQNzz0Lnj7gtoa8kstot7yayQ0H6Uj1sLOVs5elXC1uSvZrtz569Oqh2dHTctYLxR6wmH9oE+qFjP2pEpGwAGArphyDQJVVzQRIdXE0RAR0BHQIcI6AjookVAB05RsZ61I1M2AAwEdMOQaRKquKCNeDwMOVsxpj7G6vFr2GuRxq+Jex469965QW0teJAV1AUPhoT2o/Lub0HOJvOYBx6Z+XJF32Ivg3gGHThFxXrWjkzZADAQ0A1Dpkmo4oKWszwMOYuCmq9jZwS1tXg2C+jFs0NC+yH6+WwTTOZNBngrxJdbXNVqvOUT2J1b5RMCXNoH+qBiPWtHpmwAGAjohiHTJFRxQRu2Kgw5K+JKhkmKfn0TT2V5fZbocGWCMm/+pYOiX6Mng7xf2wj0QcV61o5M2QAwENANQ6ZJqOKCJjq8miACOgI6AjpEQEdAFy0COnCKivWsHZmyAWAgoKeIPXv2kN/vp379+pHL5aIXX3wx6vyVK1eovr6e+vXrR927d6eSkhJ65513oj7z4Ycf0pw5c6h3797Uu3dvmjNnDp09e7ZL/ZBpEqq4oA1pDUHO5s8Kxlg0l926XDQ3/nno3Lz79bVwHhsnhfNCYvsyG/J2/JRAwpbOYOOkdEYoqXZ0VvSXbTLI+ws/oA8q1rN2ZMoGgIGAniJ27dpFzzzzDO3YsSNuQG9paaFevXrRjh076NChQzRjxgzq168fffzxx52f8fl8NGLECNq3bx/t27ePRowYQX6/v0v9kGkSqrigDfxuAHL2zsZQjMObw2RZFg1vDsc9D+GdjfKMk6HrIG91GCdQbnmPE6APKtazdmTKBoCBgC6Azwf0K1euUN++famlpaXzWEdHB2VmZtL3vvc9IiI6fPgwuVwueuONNzo/s3//fnK5XPTee+85/rNlmoQqLmhZ9WHI2YFbmmPM2sJucc/a0hr3PIQDt2CcQGdinEAn8h4nQB9UrGftyJQNAAMBXQCfD+jvv/8+uVwuOnDgQNTnJkyYQPPmzSMios2bN1NmZmZMW5mZmfSjH/3oC/+sjo4O+uijjzo9ceIE7V5GYQAAFPtJREFUuVwuOnPmDF26dEmo58+fJ8uy6Pz588L74tSRa9ZDzmZtaY1x5BZ2q+HILYG45yHM2oJxAp2JcQKdyHuciK5n4NVTxXrW7pkzZxDQJQMBXQCfD+h79+4ll8tFJ0+ejPrcggULqLKykoiIGhsbaejQoTFtDR06lJqamr7wz6qvryeXyxVje3s7WZYFIYQQQgghNNT29nYEdMlAQBfAFwX0U6dORX3ukUceIa/XS0QsoGdlZcW0deedd1Jz8xffKoUr6FfXrO8HIWdHr1gfY/7KDWRZFuWv3BD3POyCT+tr1DgR2ZflkLd3r0zc/FWRcbJqQ1Lt6OxdkPIi4yRv1QYu7YuuZ+DVU8V61i6uoMsHAroAUnmL++eR6TmTS5fUe2ZH9KY1Jlg4oS1G99QgWZZF7qnBuOehcwsm6WvZNDZOyqYFhfbjngdCkLOl5c0JW1nFni2urGpNqh2dLapuNV7PxMgu7hMDXNoH+qBiPWtHpmwAGAjoAviiTeJaW///gn3x4sW4m8S9+eabnZ954403sElcihEdXk0QAR0BHQEdIqAjoIsWAR04RcV61o5M2QAwENBTxCeffEIHDx6kgwcPksvlonA4TAcPHqRjx44REXvNWmZmJu3cuZMOHTpEs2bNivuatVGjRtH+/ftp//79NHLkSLxmLcVkrQlDzuI96Hz1jF+nrb7SRrIsi3yljUL7UeJtgZxN5j31hfPYelI4L3R13nuvod7s5cbrv+sZsiyL/Hc9w6V9oA8q1rN2ZMoGgIGAniJeeeWVuJu1zZ8/n4jYVfT6+nrq27cvZWRkUHFxMR06dCiqjX/84x80e/Zs6tWrF/Xq1Ytmz55NZ8+e7VI/ZJqEKi5o2c+EIWeLfS0xlte2kWVZVF7bFvc8dG5RTau2eiZFrnhNCgjtR1lZE+Rs+bi1CVtV0kCWZVFVSUNS7eis6Lksg7zXE6APKtazdmTKBoCBgG4YMk1CFRc00eHVBBHQEdBlLaidKjq8miACOgK66usJ0AcV61k7MmUDwEBANwyZJqGKC1rO8jDkrMy3Lutg5d3f0taa/HqyLItq8uuF9kP0s7MmWFLRnLAV1ewZ9Iok24F6y3ucAH1QsZ61I1M2AAwEdMOQaRKquKBlPx2GnC2Y3BZj2fTI5l/Tg3HPQ+d6h/23tvpHPc2eGR31tNB+jJ0RhJytHLkyYWvGrGJf5IxZlVQ7OjtuWsB4S2axvQpKZoW4tA/0QcV61o5M2QAwENANQ6ZJqOKCJvrqsgniFne+ir7KbcIVdNEbfJkgdnHnvIu7v9V4PZMjt7hPDnBpH+iDivWsHZmyAWAgoBuGTJNQxQVNdHg1QQR0BHQEdIiAjoAuWgR04BQV61k7MmUDwEBANwyZJqGKC5ro8GqCKKg5F94SPD/MS97vLXaq6Nu/TTCZxzzwyMyXW1gL3VPYOHFPCXJpH+iDivWsHZmyAWAgoBuGTJNQxQXta/8dhpx1lzbG6KtsZpvEVTbHPQ+dK/q5TpWfGXWq6DsJTLBwQlvCuqdGgtfUYFLt6GzBJFg2LfJFzrQgl/aBPqhYz9qRKRsABgK6Ycg0CVVc0LLWhCFny/PXxFhVtI69FqloXdzz0Ln3zglqa8EDLKAXPBAS2w8JwoXujrsvkLBRX+Qk0Y7Ojp8CS2ewcVI6I8SlfaAPKtazdmTKBoCBgG4YMk1CFRc00eHVBBHQEdAR0CECOgK6aBHQgVNUrGftyJQNAAMB3TBkmoQqLmiin882wTsbQjEObwqTZVk0vCn+eejcoWvD2jqiYT1ZlkUjGtaL7cu6EOStDuNEZkX//0rgiEb2e2dEI59/D6APKtazdmTKBoCBgG4YMk1CFRe0O0JByNnbv98WY9YP2LOAWT+Ifx52we/pa9b3I+Pk+0GxfRH9f2yCOowTKLW8xwnQBxXrWTsyZQPAQEA3DJkmoYoL2sCNAcjZQeuDMQ7bwG41HLYhFPc87IIb9HXY/0TGyf+EhPcFcjaJOYD1BDqR9zgB+qBiPWtHpmwAGAjohiHTJFRxQRMdXk1QRKFklKKDFUcR0A1S4uAF9RABHThFxXrWjkzZADAQ0A1Dpkmo4oKWtToMORtvQyjer7sxybHTA9pafD8rqIvvDwntx71zg1BiCx6MbCb4YEh4X2S1qKbVeD2TAmRZFnkmBbi0D/RBxXrWjkzZADAQ0A1Dpkmo4oJ296IQ5GzB5LYYy6ZHAvr0YNzz0LmiQ7QJAb3U0ww5W95tRsJW3TCbvRXihtlJtaOz3uFPG68/dyVZlkX+3JVc2gf6oGI9a0embAAYCOiGIdMkVHFBu+fBEORsRW59jNVj15BlWVQ9dk3c89C5xb4WbS2vbSPLsqi8tk1oP8ZPDUDOlpY3J2xlVStZlkWVVa1JtaOznoJ1xusrayTLsshX1silfaAPKtazdmTKBoCBgG4YMk1CFRc00eHVBBHQEdAR0CECOgK6aBHQgVNUrGftyJQNAAMB3TBkmoQqLmiinws0wcIJbTG6p7Jb3N1T45+HXbBWX91TIuNkSlBoP8rHrYWcLfG2JGyFn32RU+FvS6odnRX9CIMMVvoiX+T4Wrm0D/RBxXrWjkzZADAQ0A1Dpkmo4oIm+hlbE/RmPRWjf+QK9izgyBVxz0PnlrmbtNXrayHLssjraxHaD9FXl03QO/SbCesfsZytJyOWJ9WOzubNDhpv4Xy2p0Xh/BCX9oE+qFjP2pEpGwAGArphyDQJVVzQRIdXE0RAR0BHQIcI6AjookVAB05RsZ61I1M2AAwEdMOQaRKquKCJvoXXBPPuD8ZYOC9SKM0LxT0PnSv6NW88leV1fKKDhQmOuy+QsCWz2HpSMiuUVDs6W1LRbLwV1ewW94rqVi7tA31QsZ61I1M2AAwEdMOQaRKquKDlPhyCnEVBzdf8WUFtLZrLxknR3JDQfrhLGyFnx84IJmzx7Mjr+GaHkmpHZ0V/USuDvPe0APqgYj1rR6ZsABgI6IYh0yRUcUETffXTBO95IBTjuEfCZFkWjXskHPc8dO7oR/Q1fxEbJ/mLwkL7cfdCKLP5j0bGyaNh4X2R1ZFLw8Y75vH1ZFkWjXl8PZf2gT6oWM/akSkbAAYCumHINAlVXNBEh1cTREBHQEdAhzxFQP9yRYdjGURAB05RsZ61I1M2AAwEdAXZuHEjDRo0iDIyMig3N5dee+01xz8r0yRUcUEbsSwMBXjPf7FC6Z7/Wi+8L6o76hv6eu8yNk7uXbZeaD9GPA55i4DO1699M2y8o5ez9WT08vVc2gf6oGI9a0embAAYCOiKsX37dkpLS6NNmzbR4cOH6bHHHqOePXvSsWPHHP28TJNQxQVt6NowFOCIBlYojWhYL7wvyrsupK0jGlnwGtEo+O8p+v8Y/kexnny5dzaGjHd4M1tPhjfz+fcA+qBiPWtHpmwAGAjoipGXl0eLFi2KOpadnU3Lly939PMyTUIVF7Qzf70VCvD/jg0my7Lo/44NFt4XKK8YJ9CJGCfQibzHCdAHFetZOzJlA8BAQFeIixcvUrdu3Wjnzp1Rx5cuXUrFxcWO2pBpEqq4oIkuGEwVBTV0IsYJdCLGCXQiAjpwior1rB2ZsgFgIKArxMmTJ8nlctHevXujjjc2NlJWVlbcn+no6KCPPvqo0+PHj5PL5aIjR47QmTNnhHr69Glqb2+n06dPC++LU/92OBsK8NShu6i9vZ1OHbpLeF+gvGKcQCdinEAn8h4nousZePVUsZ61e+TIEXK5XHTu3LlUxBngAAR0hfgsoO/bty/qeENDAw0bNizuz9TX15PL5YIQQgghhBDCuJ44cSIVcQY4AAFdIRK5xf3zV9DPnj1L77//Pp07dy7quAhPnDjRuSCI7guUW4wV6ESME+hEjBPoRIwT6FTVx8q5c+foxIkT9Omnn6YizgAHIKArRl5eHi1evDjqWE5OjuNN4mTio4/wzAtwBsYKcALGCXACxglwAsYJcArGCrjaIKArxmevWdu8eTMdPnyYli1bRj179qSjR4+K7lqXwYIGnIKxApyAcQKcgHECnIBxApyCsQKuNgjoCrJx40YaOHAgpaenU25uLu3Zs0d0lxICCxpwCsYKcALGCXACxglwAsYJcArGCrjaIKADYXR0dFB9fT11dHSI7gqQHIwV4ASME+AEjBPgBIwT4BSMFXC1QUAHAAAAAAAAAAAkAAEdAAAAAAAAAACQAAR0AAAAAAAAAABAAhDQAQAAAAAAAAAACUBABwAAAAAAAAAAJAABHXBl48aNNGjQIMrIyKDc3Fx67bXX/uPnX3jhBcrJyaH09HTKycmhnTt3pqinQCRdGSc/+MEPqLCwkG688Ua68cYbyePx0JtvvpnC3gKRdHVN+Yxt27aRy+WiiRMncu4hkIGujpOzZ8/SkiVLqG/fvpSRkUHZ2dn0i1/8IkW9BaLo6jhZv349ZWVlUffu3al///60bNkyunDhQop6C0SwZ88e8vv91K9fP3K5XPTiiy9+6c+8+uqrlJubSxkZGXTHHXfQs88+m4KeAp1AQAfc2L59O6WlpdGmTZvo8OHD9Nhjj1HPnj3p2LFjcT+/b98+6tatGzU1NdG7775LTU1NdN1119Ebb7yR4p6DVNLVcXL//ffTxo0b6eDBg/Tuu+/Sgw8+SJmZmfTXv/41xT0HqaarY+Uzjh49SrfddhsVFRUhoBtAV8fJxYsXacyYMVRdXU2vv/46HT16lH7729/SW2+9leKeg1TS1XHyk5/8hDIyMmjr1q105MgR+tWvfkX9+vWjZcuWpbjnIJXs2rWLnnnmGdqxY4ejgP7BBx/Q9ddfT4899hgdPnyYNm3aRGlpafTCCy+kqMdABxDQATfy8vJo0aJFUceys7Np+fLlcT8/ffp08vl8Uce8Xi/NnDmTWx+BeLo6Tj7P5cuXqVevXrRlyxYe3QMSkchYuXz5MhUUFNAPf/hDmj9/PgK6AXR1nDz77LM0ePBgunTpUiq6ByShq+Pk0UcfJbfbHXXsiSeeoMLCQm59BHLhJKA/9dRTlJ2dHXVs4cKFNHbsWJ5dA5qBgA64cPHiRerWrVvMLepLly6l4uLiuD8zYMAACofDUcfC4TDdfvvt3PoJxJLIOPk8H3/8MXXv3p1+9rOf8egikIREx8qqVato0qRJREQI6AaQyDipqqqi2bNn04IFC+iWW26h4cOHU2NjI12+fDkVXQYCSGScbNu2jTIzMzsfqXr//fcpOzubmpubufcXyIGTgF5UVERLly6NOrZz50667rrr8CUgcAwCOuDCyZMnyeVy0d69e6OONzY2UlZWVtyfSUtLo61bt0Yd27p1K6Wnp3PrJxBLIuPk8yxZsoSGDBmC5wA1J5Gx8vrrr9Ntt91Gf//734kIAd0EEhknw4YNo4yMDHrooYfo97//PW3bto369OlDa9asSUWXgQAS/d3z7W9/m9LS0ui6664jl8tFixcv5t1VIBFOAvrQoUOpsbEx6tjevXvJ5XLRqVOneHYPaAQCOuDCZ7/89u3bF3W8oaGBhg0bFvdn0tLSqL29PerYZ898AT1JZJzYaW1tpa985Sv0hz/8gVcXgSR0dax8/PHHNGjQINq1a1fnMQR0/UlkTRk6dCgNGDAg6op5KBSivn37cu0rEEci4+SVV16hr371q7Rp0yZ6++23aefOnTRgwABau3ZtKroMJMBpQG9qaoo69vrrr5PL5aLTp0/z7B7QCAR0wAXc4g6ckMwt7oFAgDIzM+l3v/sdzy4CSejqWDl48CC5XC7q1q1bp9dccw1dc8011K1bN/rLX/6Sqq6DFJLImlJcXEwejyfq2K5du8jlctHFixe59RWII5FxUlhYSE8++WTUsR//+MfUo0cP+vTTT7n1FcgDbnEHqQIBHXAjLy8v5vavnJyc/7hJXFVVVdQxn8+HTeI0p6vjhIiora2NevfuTfv37+fdPSARXRkrFy5coEOHDkU5ceJEcrvddOjQIQQvjenqmrJixQoaOHBgVMjasGED9evXj2s/gVi6Ok5yc3PpqaeeijrW3t5O3bt3x34FhuB0k7icnJyoY4sWLcImcaBLIKADbnz2CpPNmzfT4cOHadmyZdSzZ086evQoERHNnTs36hfh3r17qVu3btTS0kLvvvsutbS04DVrBtDVcdLa2krp6en0wgsv0OnTpzv95JNPRP0VQIro6lj5PLjF3Qy6Ok6OHz9ON9xwA9XV1dEf//hH+vnPf0633HILNTQ0iPorgBTQ1XFSX19PvXr1om3bttEHH3xAL730Eg0ZMoSmT58u6q8AUsAnn3xCBw8e7LwrKxwO08GDBztfx7d8+XKaO3du5+c/e83a448/TocPH6bNmzfjNWugyyCgA65s3LiRBg4cSOnp6ZSbm0t79uzpPFdSUkLz58+P+vxPf/pTGjZsGKWlpVF2djbt2LEjxT0GIujKOBk4cCC5XK4Y6+vrU99xkHK6uqbYQUA3h66Ok3379lF+fj5lZGTQ4MGDsYu7IXRlnPz73/+m1atX05AhQ6h79+40YMAAWrJkCZ09e1ZAz0GqeOWVV+LWHJ+Njfnz51NJSUnUz7z66qs0evRoSk9Pp0GDBtGzzz6b+o4DpUFABwAAAAAAAAAAJAABHQAAAAAAAAAAkAAEdAAAAAAAAAAAQAIQ0AEAAAAAAAAAAAlAQAcAAAAAAAAAACQAAR0AAAAAAAAAAJAABHQAAAAAAAAAAEACENABAAAAAAAAAAAJQEAHAAAAAAAAAAAkAAEdAAAAAAAAAACQAAR0AAAAAAAAAABAAhDQAQAAAAAAAAAACUBABwAAAAAAAAAAJAABHQAAAAAAAAAAkAAEdAAAAAAAAAAAQAIQ0AEAAAAAAAAAAAlAQAcAAAAAAAAAACQAAR0AAAAAAAAAAJAABHQAAAAAAAAAAEACENABAAAAAAAAAAAJQEAHAAAAAAAAAAAkAAEdAAAAAAAAAACQAAR0AAAAAAAAAABAAhDQAQAAAAAAAAAACUBABwAAAAAAAAAAJAABHQAAAAAAAAAAkAAEdAAAAAAAAAAAQAIQ0AEAAAAAAAAAAAlAQAcAAAAAAAAAACQAAR0AAAAAAAAAAJAABHQAAAAAAAAAAEACENABAAAAAAAAAAAJQEAHAAAAAAAAAAAkAAEdAAAAAAAAAACQgP8HNitBWhKmkhgAAAAASUVORK5CYII=\" width=\"1000\">" + ], + "text/plain": [ + "<IPython.core.display.HTML object>" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "data = plot_data(offx=4, signed=True, channels=1)\n", + "#print(''.join(str(x) for x in data[4:][3::4]))" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "scrolled": false + }, + "outputs": [ + { + "ename": "FileNotFoundError", + "evalue": "[Errno 2] No such file or directory: '/tmp/foo'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mFileNotFoundError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m<ipython-input-32-d8e3fa510bf1>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0mplotdata\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m[\u001b[0m\u001b[0msum\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvals\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m+\u001b[0m\u001b[0mdelta\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m/\u001b[0m\u001b[0mdelta\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mi\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mlen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mvals\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdelta\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 14\u001b[0m \u001b[0mplt\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mplot\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mplotdata\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 15\u001b[0;31m \u001b[0mplot_avg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m<ipython-input-32-d8e3fa510bf1>\u001b[0m in \u001b[0;36mplot_avg\u001b[0;34m()\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mplot_avg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m \u001b[0;32mwith\u001b[0m \u001b[0mopen\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'/tmp/foo'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'rb'\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0mf\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 5\u001b[0m \u001b[0mvals\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mfrombuffer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mread\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'uint16'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mFileNotFoundError\u001b[0m: [Errno 2] No such file or directory: '/tmp/foo'" + ] + } + ], + "source": [ + "import random, struct, numpy as np\n", + "\n", + "def plot_avg():\n", + " with open('/tmp/foo', 'rb') as f:\n", + " vals = np.frombuffer(f.read(), dtype='uint16')\n", + " \n", + " vals = vals.copy()\n", + " idx = 1\n", + " vals &= 1<<idx\n", + " vals >>= idx\n", + " \n", + " delta = 10000\n", + " plotdata = [sum(vals[i:i+delta])/delta for i in range(0, len(vals), delta)]\n", + " plt.plot(plotdata)\n", + "plot_avg()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.5" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/gm_platform/fw/adc.c b/gm_platform/fw/adc.c new file mode 100644 index 0000000..547089b --- /dev/null +++ b/gm_platform/fw/adc.c @@ -0,0 +1,125 @@ +/* Megumin LED display firmware + * Copyright (C) 2018 Sebastian Götte <code@jaseg.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "adc.h" + +#include <stdbool.h> +#include <stdlib.h> + +volatile uint16_t adc_buf[ADC_BUFSIZE]; + +static void adc_dma_init(int burstlen); +static void adc_timer_init(int psc, int ivl); + + +/* Mode that can be used for debugging */ +void adc_configure_scope_mode(int sampling_interval_ns) { + adc_dma_init(sizeof(adc_buf)/sizeof(adc_buf[0])); + + /* Clock from PCLK/4 instead of the internal exclusive high-speed RC oscillator. */ + ADC1->CFGR2 = (2<<ADC_CFGR2_CKMODE_Pos); /* Use PCLK/4=12MHz */ + /* Sampling time 239.5 ADC clock cycles -> total conversion time 38.5us*/ + ADC1->SMPR = (7<<ADC_SMPR_SMP_Pos); + + /* Setup DMA and triggering */ + /* Trigger from TIM1 TRGO */ + ADC1->CFGR1 = ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG | (2<<ADC_CFGR1_EXTEN_Pos) | (1<<ADC_CFGR1_EXTSEL_Pos); + ADC1->CHSELR = ADC_CHSELR_CHSEL2; + /* Perform self-calibration */ + ADC1->CR |= ADC_CR_ADCAL; + while (ADC1->CR & ADC_CR_ADCAL) + ; + /* Enable conversion */ + ADC1->CR |= ADC_CR_ADEN; + ADC1->CR |= ADC_CR_ADSTART; + + /* An ADC conversion takes 1.1667us, so to be sure we don't get data overruns we limit sampling to every 1.5us. + Since we don't have a spare PLL to generate the ADC sample clock and re-configuring the system clock just for this + would be overkill we round to 250ns increments. The minimum sampling rate is about 60Hz due to timer resolution. */ + int cycles = sampling_interval_ns > 1500 ? sampling_interval_ns/250 : 6; + if (cycles > 0xffff) + cycles = 0xffff; + adc_timer_init(12/*250ns/tick*/, cycles); +} + +/* FIXME figure out the proper place to configure this. */ +#define ADC_TIMER_INTERVAL_US 20 + +static void adc_dma_init(int burstlen) { + /* Configure DMA 1 Channel 1 to get rid of all the data */ + DMA1_Channel1->CPAR = (unsigned int)&ADC1->DR; + DMA1_Channel1->CMAR = (unsigned int)&adc_buf; + DMA1_Channel1->CNDTR = burstlen; + DMA1_Channel1->CCR = (0<<DMA_CCR_PL_Pos); + DMA1_Channel1->CCR |= + DMA_CCR_CIRC /* circular mode so we can leave it running indefinitely */ + | (1<<DMA_CCR_MSIZE_Pos) /* 16 bit */ + | (1<<DMA_CCR_PSIZE_Pos) /* 16 bit */ + | DMA_CCR_MINC + | DMA_CCR_TCIE; /* Enable transfer complete interrupt. */ + + /* triggered on transfer completion. We use this to process the ADC data */ + NVIC_EnableIRQ(DMA1_Channel1_IRQn); + NVIC_SetPriority(DMA1_Channel1_IRQn, 2<<5); + + DMA1_Channel1->CCR |= DMA_CCR_EN; /* Enable channel */ +} + +static void adc_timer_init(int psc, int ivl) { + TIM1->BDTR = TIM_BDTR_MOE; /* MOE is needed even though we only "output" a chip-internal signal TODO: Verify this. */ + TIM1->CCMR2 = (6<<TIM_CCMR2_OC4M_Pos); /* PWM Mode 1 to get a clean trigger signal */ + TIM1->CCER = TIM_CCER_CC4E; /* Enable capture/compare unit 4 connected to ADC */ + TIM1->CCR4 = 1; /* Trigger at start of timer cycle */ + /* Set prescaler and interval */ + TIM1->PSC = psc-1; + TIM1->ARR = ivl-1; + /* Preload all values */ + TIM1->EGR |= TIM_EGR_UG; + TIM1->CR1 = TIM_CR1_ARPE; + /* And... go! */ + TIM1->CR1 |= TIM_CR1_CEN; +} + +/* This acts as a no-op that provides a convenient point to set a breakpoint for the debug scope logic */ +static void gdb_dump(void) { +} + +void DMA1_Channel1_IRQHandler(void) { + /* Clear the interrupt flag */ + DMA1->IFCR |= DMA_IFCR_CGIF1; + gdb_dump(); + + /* + static int debug_buf_pos = 0; + if (st->sync) { + if (debug_buf_pos < NCH) { + debug_buf_pos = NCH; + } else { + adc_buf[debug_buf_pos++] = symbol; + + if (debug_buf_pos >= sizeof(adc_buf)/sizeof(adc_buf[0])) { + debug_buf_pos = 0; + st->sync = 0; + gdb_dump(); + for (int i=0; i<sizeof(adc_buf)/sizeof(adc_buf[0]); i++) + adc_buf[i] = -255; + } + } + } + */ +} + diff --git a/gm_platform/fw/adc.h b/gm_platform/fw/adc.h new file mode 100644 index 0000000..c526858 --- /dev/null +++ b/gm_platform/fw/adc.h @@ -0,0 +1,28 @@ +/* Megumin LED display firmware + * Copyright (C) 2018 Sebastian Götte <code@jaseg.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __ADC_H__ +#define __ADC_H__ + +#include "global.h" + +extern volatile uint16_t adc_buf[ADC_BUFSIZE]; + +void adc_init(void); +void adc_configure_scope_mode(int sampling_interval_ns); + +#endif/*__ADC_H__*/ diff --git a/gm_platform/fw/base.c b/gm_platform/fw/base.c new file mode 100644 index 0000000..8e7c03b --- /dev/null +++ b/gm_platform/fw/base.c @@ -0,0 +1,25 @@ + +#include <unistd.h> +#include <stdbool.h> + +int __errno = 0; +void *_impure_ptr = NULL; + +void __sinit(void) { +} + +void *memset(void *s, int c, size_t n) { + char *end = (char *)s + n; + for (char *p = (char *)s; p < end; p++) + *p = (char)c; + return s; +} + +size_t strlen(const char *s) { + const char *start = s; + while (*s++); + return s - start - 1; +} + +void __assert_func(bool value) { +} diff --git a/gm_platform/fw/cmsis_exports.c b/gm_platform/fw/cmsis_exports.c new file mode 100644 index 0000000..39874b5 --- /dev/null +++ b/gm_platform/fw/cmsis_exports.c @@ -0,0 +1,48 @@ +#ifndef __GENERATED_CMSIS_HEADER_EXPORTS__ +#define __GENERATED_CMSIS_HEADER_EXPORTS__ + +#include <stm32f030x6.h> + +/* stm32f030x6.h */ +TIM_TypeDef *tim3 = TIM3; +TIM_TypeDef *tim14 = TIM14; +RTC_TypeDef *rtc = RTC; +WWDG_TypeDef *wwdg = WWDG; +IWDG_TypeDef *iwdg = IWDG; +I2C_TypeDef *i2c1 = I2C1; +PWR_TypeDef *pwr = PWR; +SYSCFG_TypeDef *syscfg = SYSCFG; +EXTI_TypeDef *exti = EXTI; +ADC_TypeDef *adc1 = ADC1; +ADC_Common_TypeDef *adc1_common = ADC1_COMMON; +ADC_Common_TypeDef *adc = ADC; +TIM_TypeDef *tim1 = TIM1; +SPI_TypeDef *spi1 = SPI1; +USART_TypeDef *usart1 = USART1; +TIM_TypeDef *tim16 = TIM16; +TIM_TypeDef *tim17 = TIM17; +DBGMCU_TypeDef *dbgmcu = DBGMCU; +DMA_TypeDef *dma1 = DMA1; +DMA_Channel_TypeDef *dma1_channel1 = DMA1_Channel1; +DMA_Channel_TypeDef *dma1_channel2 = DMA1_Channel2; +DMA_Channel_TypeDef *dma1_channel3 = DMA1_Channel3; +DMA_Channel_TypeDef *dma1_channel4 = DMA1_Channel4; +DMA_Channel_TypeDef *dma1_channel5 = DMA1_Channel5; +FLASH_TypeDef *flash = FLASH; +OB_TypeDef *ob = OB; +RCC_TypeDef *rcc = RCC; +CRC_TypeDef *crc = CRC; +GPIO_TypeDef *gpioa = GPIOA; +GPIO_TypeDef *gpiob = GPIOB; +GPIO_TypeDef *gpioc = GPIOC; +GPIO_TypeDef *gpiod = GPIOD; +GPIO_TypeDef *gpiof = GPIOF; + +#include <core_cm0.h> + +/* core_cm0.h */ +SCB_Type *scb = SCB; +SysTick_Type *systick = SysTick; +NVIC_Type *nvic = NVIC; + +#endif//__GENERATED_CMSIS_HEADER_EXPORTS__ diff --git a/gm_platform/fw/cobs.c b/gm_platform/fw/cobs.c new file mode 100644 index 0000000..22dcac0 --- /dev/null +++ b/gm_platform/fw/cobs.c @@ -0,0 +1,293 @@ + +#include "serial.h" +#include "cobs.h" + +/*@ requires \valid(dst + (0..dstlen-1)); + @ requires \valid_read(src + (0..srclen-1)); + @ requires \separated(dst + (0..dstlen-1), src + (0..srclen-1)); + @ + @ behavior valid: + @ assumes 0 <= srclen <= 254; + @ assumes 0 <= dstlen <= 65535; + @ assumes dstlen >= srclen+2; + @ assigns dst[0..srclen+1]; + @ ensures \forall integer i; (0 <= i < srclen && \old(src[i]) != 0) ==> dst[i+1] == src[i]; + @ ensures \result == srclen+2; + @ ensures \forall integer i; 0 <= i <= srclen ==> dst[i] != 0; + @ ensures dst[srclen+1] == 0; + @ + @ behavior invalid: + @ assumes srclen < 0 || srclen > 254 + @ || dstlen < 0 || dstlen > 65535 + @ || dstlen < srclen+2; + @ assigns \nothing; + @ ensures \result == -1; + @ + @ complete behaviors; + @ disjoint behaviors; + @*/ +ssize_t cobs_encode(char *dst, size_t dstlen, char *src, size_t srclen) { + if (dstlen > 65535 || srclen > 254) + return -1; + //@ assert 0 <= dstlen <= 65535 && 0 <= srclen <= 254; + + if (dstlen < srclen+2) + return -1; + //@ assert 0 <= srclen < srclen+2 <= dstlen; + + size_t p = 0; + /*@ loop invariant 0 <= p <= srclen+1; + @ loop invariant \forall integer i; 0 <= i < p ==> dst[i] != 0; + @ loop invariant \forall integer i; 0 < i < p ==> (src[i-1] != 0 ==> dst[i] == src[i-1]); + @ loop assigns p, dst[0..srclen+1]; + @ loop variant srclen-p+1; + @*/ + while (p <= srclen) { + + char val; + if (p != 0 && src[p-1] != 0) { + val = src[p-1]; + + } else { + size_t q = p; + /*@ loop invariant 0 <= p <= q <= srclen; + @ loop invariant \forall integer i; p <= i < q ==> src[i] != 0; + @ loop assigns q; + @ loop variant srclen-q; + @*/ + while (q < srclen && src[q] != 0) + q++; + //@ assert q == srclen || src[q] == 0; + //@ assert q <= srclen <= 254; + val = (char)q-p+1; + //@ assert val != 0; + } + + dst[p] = val; + p++; + } + + dst[p] = 0; + //@ assert p == srclen+1; + + return srclen+2; +} + +int cobs_encode_usart(char *src, size_t srclen) { + if (srclen > 254) + return -1; + //@ assert 0 <= srclen <= 254; + + size_t p = 0; + /*@ loop invariant 0 <= p <= srclen+1; + @ loop assigns p; + @ loop variant srclen-p+1; + @*/ + while (p <= srclen) { + + char val; + if (p != 0 && src[p-1] != 0) { + val = src[p-1]; + + } else { + size_t q = p; + /*@ loop invariant 0 <= p <= q <= srclen; + @ loop invariant \forall integer i; p <= i < q ==> src[i] != 0; + @ loop assigns q; + @ loop variant srclen-q; + @*/ + while (q < srclen && src[q] != 0) + q++; + //@ assert q == srclen || src[q] == 0; + //@ assert q <= srclen <= 254; + val = (char)q-p+1; + //@ assert val != 0; + } + + usart_putc(val); + p++; + } + + usart_putc(0); + //@ assert p == srclen+1; + + return 0; +} + +/*@ requires \valid(dst + (0..dstlen-1)); + @ requires \valid_read(src + (0..srclen-1)); + @ requires \separated(dst + (0..dstlen-1), src + (0..srclen-1)); + @ + @ behavior maybe_valid_frame: + @ assumes 1 <= srclen <= dstlen <= 65535; + @ assumes \exists integer j; j > 0 && \forall integer i; 0 <= i < j ==> src[i] != 0; + @ assumes \exists integer i; 0 <= i < srclen && src[i] == 0; + @ assigns dst[0..dstlen-1]; + @ ensures \result >= 0 || \result == -3; + @ ensures \result >= 0 ==> src[\result+1] == 0; + @ ensures \result >= 0 ==> (\forall integer i; 0 <= i < \result ==> src[i] != 0); + @ + @ behavior invalid_frame: + @ assumes 1 <= srclen <= dstlen <= 65535; + @ assumes src[0] == 0 || \forall integer i; 0 <= i < srclen ==> src[i] != 0; + @ assigns dst[0..dstlen-1]; + @ ensures \result == -2; + @ + @ behavior invalid_buffers: + @ assumes dstlen < 0 || dstlen > 65535 + @ || srclen < 1 || srclen > 65535 + @ || dstlen < srclen; + @ assigns \nothing; + @ ensures \result == -1; + @ + @ complete behaviors; + @ disjoint behaviors; + @*/ +ssize_t cobs_decode(char *dst, size_t dstlen, char *src, size_t srclen) { + if (dstlen > 65535 || srclen > 65535) + return -1; + + if (srclen < 1) + return -1; + + if (dstlen < srclen) + return -1; + + size_t p = 1; + size_t c = (unsigned char)src[0]; + //@ assert 0 <= c < 256; + //@ assert 0 <= c; + //@ assert c < 256; + if (c == 0) + return -2; /* invalid framing. An empty frame would be [...] 00 01 00, not [...] 00 00 */ + //@ assert c >= 0; + //@ assert c != 0; + //@ assert c <= 257; + //@ assert c > 0; + //@ assert c >= 0 && c != 0 ==> c > 0; + + /*@ //loop invariant \forall integer i; 0 <= i <= p ==> (i == srclen || src[i] != 0); + @ loop invariant \forall integer i; 1 <= i < p ==> src[i] != 0; + @ loop invariant c > 0; + @ loop invariant 1 <= p <= srclen <= dstlen <= 65535; + @ loop invariant \separated(dst + (0..dstlen-1), src + (0..srclen-1)); + @ loop invariant \valid_read(src + (0..srclen-1)); + @ loop invariant \forall integer i; 1 <= i <= srclen ==> \valid(dst + i - 1); + @ loop assigns dst[0..dstlen-1], p, c; + @ loop variant srclen-p; + @*/ + while (p < srclen && src[p]) { + char val; + c--; + + //@ assert src[p] != 0; + if (c == 0) { + c = (unsigned char)src[p]; + val = 0; + } else { + val = src[p]; + } + + //@ assert 0 <= p-1 <= dstlen-1; + dst[p-1] = val; + p++; + } + + if (p == srclen) + return -2; /* Invalid framing. The terminating null byte should always be present in the input buffer. */ + + if (c != 1) + return -3; /* Invalid framing. The skip counter does not hit the end of the frame. */ + + //@ assert 0 < p <= srclen <= 65535; + //@ assert src[p] == 0; + //@ assert \forall integer i; 1 <= i < p ==> src[i] != 0; + return p-1; +} + +void cobs_decode_incremental_initialize(struct cobs_decode_state *state) { + state->p = 0; + state->c = 0; +} + +int cobs_decode_incremental(struct cobs_decode_state *state, char *dst, size_t dstlen, char src) { + if (state->p == 0) { + if (src == 0) + goto empty_errout; /* invalid framing. An empty frame would be [...] 00 01 00, not [...] 00 00 */ + state->c = (unsigned char)src; + state->p++; + return 0; + } + + if (!src) { + if (state->c != 1) + goto errout; /* Invalid framing. The skip counter does not hit the end of the frame. */ + int rv = state->p-1; + cobs_decode_incremental_initialize(state); + return rv; + } + + char val; + state->c--; + + if (state->c == 0) { + state->c = (unsigned char)src; + val = 0; + } else { + val = src; + } + + size_t pos = state->p-1; + if (pos >= dstlen) + return -2; /* output buffer too small */ + dst[pos] = val; + state->p++; + return 0; + +errout: + cobs_decode_incremental_initialize(state); + return -1; + +empty_errout: + cobs_decode_incremental_initialize(state); + return -3; +} + +#ifdef VALIDATION +/*@ + @ requires 0 <= d < 256; + @ assigns \nothing; + @*/ +size_t test(char foo, unsigned int d) { + unsigned int c = (unsigned char)foo; + if (c != 0) { + //@ assert c < 256; + //@ assert c >= 0; + //@ assert c != 0; + //@ assert c > 0; + } + if (d != 0) { + //@ assert d >= 0; + //@ assert d != 0; + //@ assert d > 0; + } + return c + d; +} + +#include <__fc_builtin.h> + +void main(void) { + char inbuf[254]; + char cobsbuf[256]; + char outbuf[256]; + + size_t range = Frama_C_interval(0, sizeof(inbuf)); + Frama_C_make_unknown((char *)inbuf, range); + + cobs_encode(cobsbuf, sizeof(cobsbuf), inbuf, sizeof(inbuf)); + cobs_decode(outbuf, sizeof(outbuf), cobsbuf, sizeof(cobsbuf)); + + //@ assert \forall integer i; 0 <= i < sizeof(inbuf) ==> outbuf[i] == inbuf[i]; +} +#endif//VALIDATION + diff --git a/gm_platform/fw/cobs.h b/gm_platform/fw/cobs.h new file mode 100644 index 0000000..40f7955 --- /dev/null +++ b/gm_platform/fw/cobs.h @@ -0,0 +1,23 @@ +#ifndef __COBS_H__ +#define __COBS_H__ + +#include <stdint.h> +#include <unistd.h> +#include <string.h> + + +struct cobs_decode_state { + size_t p; + size_t c; +}; + + +ssize_t cobs_encode(char *dst, size_t dstlen, char *src, size_t srclen); +ssize_t cobs_decode(char *dst, size_t dstlen, char *src, size_t srclen); + +int cobs_encode_usart(char *src, size_t srclen); + +void cobs_decode_incremental_initialize(struct cobs_decode_state *state); +int cobs_decode_incremental(struct cobs_decode_state *state, char *dst, size_t dstlen, char src); + +#endif//__COBS_H__ diff --git a/gm_platform/fw/global.h b/gm_platform/fw/global.h new file mode 100644 index 0000000..5fedde7 --- /dev/null +++ b/gm_platform/fw/global.h @@ -0,0 +1,52 @@ +/* Megumin LED display firmware + * Copyright (C) 2018 Sebastian Götte <code@jaseg.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __GLOBAL_H__ +#define __GLOBAL_H__ + +/* Workaround for sub-par ST libraries */ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#include <stm32f0xx.h> +#include <stm32f0xx_ll_utils.h> +#include <stm32f0xx_ll_spi.h> +#pragma GCC diagnostic pop + +#include <system_stm32f0xx.h> + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <unistd.h> + +/* Microcontroller part number: STM32F030F4P6 */ + +/* Things used for module status reporting. */ +#define FIRMWARE_VERSION 1 +#define HARDWARE_VERSION 0 + +#define TS_CAL1 (*(uint16_t *)0x1FFFF7B8) +#define VREFINT_CAL (*(uint16_t *)0x1FFFF7BA) + +#define ADC_BUFSIZE 1024 + +extern volatile unsigned int sys_time; +extern volatile unsigned int sys_time_seconds; + +#define UNUSED(var) ((void)var) + +#endif/*__GLOBAL_H__*/ diff --git a/gm_platform/fw/main.bin b/gm_platform/fw/main.bin Binary files differnew file mode 100755 index 0000000..e2b0cdc --- /dev/null +++ b/gm_platform/fw/main.bin diff --git a/gm_platform/fw/main.c b/gm_platform/fw/main.c new file mode 100644 index 0000000..d2bc33c --- /dev/null +++ b/gm_platform/fw/main.c @@ -0,0 +1,175 @@ +/* Megumin LED display firmware + * Copyright (C) 2018 Sebastian Götte <code@jaseg.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "global.h" +#include "adc.h" +#include "serial.h" + + +volatile unsigned int sys_time_seconds = 0; + +void update_leds() { + +} + +volatile union { + struct { + unsigned int usb, ocxo, error, _nc1, _nc2, _nc3, pps, sd_card; + }; + unsigned int arr[0]; +} leds; + +int main(void) { + RCC->CR |= RCC_CR_HSEON; + while (!(RCC->CR&RCC_CR_HSERDY)); + RCC->CFGR &= ~RCC_CFGR_PLLMUL_Msk & ~RCC_CFGR_SW_Msk & ~RCC_CFGR_PPRE_Msk & ~RCC_CFGR_HPRE_Msk; + RCC->CFGR |= ((6-2)<<RCC_CFGR_PLLMUL_Pos) | RCC_CFGR_PLLSRC_HSE_PREDIV; /* PLL x6 -> 48.0MHz */ + RCC->CR |= RCC_CR_PLLON; + while (!(RCC->CR&RCC_CR_PLLRDY)); + RCC->CFGR |= (2<<RCC_CFGR_SW_Pos); + SystemCoreClockUpdate(); + SysTick_Config(SystemCoreClock/10); /* 100ms interval */ + NVIC_EnableIRQ(SysTick_IRQn); + NVIC_SetPriority(SysTick_IRQn, 3<<5); + + /* Turn on lots of neat things */ + RCC->AHBENR |= RCC_AHBENR_DMAEN | RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_FLITFEN; + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_ADCEN | RCC_APB2ENR_SPI1EN | RCC_APB2ENR_DBGMCUEN |\ + RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM16EN | RCC_APB2ENR_USART1EN; + RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; + + GPIOA->MODER |= + (3<<GPIO_MODER_MODER2_Pos) /* PA2 - LINE_MEAS */ + | (1<<GPIO_MODER_MODER3_Pos) /* PA3 - LED_STB */ + | (1<<GPIO_MODER_MODER4_Pos) /* PA4 - SD_CS */ + | (2<<GPIO_MODER_MODER5_Pos) /* PA5 - SCK */ + | (2<<GPIO_MODER_MODER6_Pos) /* PA6 - MISO */ + | (2<<GPIO_MODER_MODER7_Pos) /* PA7 - MOSI */ + | (2<<GPIO_MODER_MODER9_Pos) /* PA9 - HOST_RX */ + | (2<<GPIO_MODER_MODER10_Pos);/* PA10 - HOST_TX */ + + /* Set shift register IO GPIO output speed */ + GPIOA->OSPEEDR |= + (2<<GPIO_OSPEEDR_OSPEEDR3_Pos) /* LED_STB */ + | (2<<GPIO_OSPEEDR_OSPEEDR4_Pos) /* SD_CS */ + | (2<<GPIO_OSPEEDR_OSPEEDR5_Pos) /* SCK */ + | (2<<GPIO_OSPEEDR_OSPEEDR7_Pos) /* MOSI */ + | (2<<GPIO_OSPEEDR_OSPEEDR9_Pos); /* HOST_RX */ + + GPIOA->AFR[0] = (0<<GPIO_AFRL_AFRL5_Pos) | (0<<GPIO_AFRL_AFRL6_Pos) | (0<<GPIO_AFRL_AFRL7_Pos); + GPIOA->AFR[1] = (1<<8) | (1<<4); + + GPIOB->MODER |= + (0<<GPIO_MODER_MODER1_Pos); /* PB0 - LINE_POL */ + + SPI1->CR1 = + SPI_CR1_SSM + | SPI_CR1_SSI + | (4<<SPI_CR1_BR_Pos) /* /32 ~1.5MHz */ + | SPI_CR1_MSTR; + SPI1->CR2 = (7<<SPI_CR2_DS_Pos); + SPI1->CR1 |= SPI_CR1_SPE; + + NVIC_EnableIRQ(SPI1_IRQn); + NVIC_SetPriority(SPI1_IRQn, 2<<5); + + TIM16->CR2 = 0; + TIM16->DIER = TIM_DIER_UIE; + TIM16->PSC = 48-1; /* 1us */ + TIM16->ARR = 1000-1; /* 1ms */ + TIM16->CR1 = TIM_CR1_CEN; + + NVIC_EnableIRQ(TIM16_IRQn); + NVIC_SetPriority(TIM16_IRQn, 2<<5); + + adc_configure_scope_mode(1000000); + + usart_dma_init(); + + while (42) { + char *data = "FOOBAR\n"; + usart_send_packet((uint8_t*)data, 8); + for (int i=0; i<100000; i++); + //int pol = GPIOB->IDR & (1<<1); /* Sample current polarity */ + //leds.error = pol ? 100 : 0; + //for (int i=0; i<10000; i++) ; + //leds.error = 100; + } +} + +void SPI1_IRQHandler(void) { + if (SPI1->SR & SPI_SR_TXE) { + /* LED_STB */ + GPIOA->BSRR = 1<<3; + SPI1->CR2 &= ~SPI_CR2_TXEIE; + } +} + +void TIM16_IRQHandler(void) { + static int leds_update_counter = 0; + if (TIM16->SR & TIM_SR_UIF) { + TIM16->SR &= ~TIM_SR_UIF; + + uint8_t bits = 0, mask = 1; + for (size_t i=0; i<sizeof(leds)/sizeof(leds.arr[0]); i++) { + if (leds.arr[i]) { + leds.arr[i]--; + bits |= mask; + } + mask <<= 1; + } + + if (leds_update_counter++ == 10) { + leds_update_counter = 0; + + /* Workaround for SPI hardware bug: Even if configured to 8-bit mode, the SPI will do a 16-bit transfer if the + * data register is accessed through a 16-bit write. Unfortunately, the STMCube register defs define DR as an + * uint16_t, so we have to do some magic here to force an 8-bit write. */ + *((volatile uint8_t*)&(SPI1->DR)) = bits; + SPI1->CR2 |= SPI_CR2_TXEIE; + GPIOA->BRR = 1<<3; + } + } +} + +void NMI_Handler(void) { + asm volatile ("bkpt"); +} + +void HardFault_Handler(void) __attribute__((naked)); +void HardFault_Handler() { + asm volatile ("bkpt"); +} + +void SVC_Handler(void) { + asm volatile ("bkpt"); +} + + +void PendSV_Handler(void) { + asm volatile ("bkpt"); +} + +void SysTick_Handler(void) { + static int n = 0; + if (n++ == 10) { + n = 0; + sys_time_seconds++; + leds.pps = 100; /* ms */ + } +} + diff --git a/gm_platform/fw/main.c.bak b/gm_platform/fw/main.c.bak new file mode 100644 index 0000000..07d065d --- /dev/null +++ b/gm_platform/fw/main.c.bak @@ -0,0 +1,162 @@ +/* Megumin LED display firmware + * Copyright (C) 2018 Sebastian Götte <code@jaseg.net> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "global.h" + +#include "adc.h" + +volatile unsigned int sys_time = 0; +volatile unsigned int sys_time_seconds = 0; + +void TIM1_BRK_UP_TRG_COM_Handler() { + TIM1->SR &= ~TIM_SR_UIF_Msk; +} + +int main(void) { + RCC->CR |= RCC_CR_HSEON; + while (!(RCC->CR&RCC_CR_HSERDY)); + RCC->CFGR &= ~RCC_CFGR_PLLMUL_Msk & ~RCC_CFGR_SW_Msk & ~RCC_CFGR_PPRE_Msk & ~RCC_CFGR_HPRE_Msk; + RCC->CFGR |= ((6-2)<<RCC_CFGR_PLLMUL_Pos) | RCC_CFGR_PLLSRC_HSE_PREDIV; /* PLL x6 -> 48.0MHz */ + RCC->CR |= RCC_CR_PLLON; + while (!(RCC->CR&RCC_CR_PLLRDY)); + RCC->CFGR |= (2<<RCC_CFGR_SW_Pos); + SystemCoreClockUpdate(); + SysTick_Config(SystemCoreClock/1000); /* 1ms interval */ + + /* Turn on lots of neat things */ + RCC->AHBENR |= RCC_AHBENR_DMAEN | RCC_AHBENR_GPIOAEN | RCC_AHBENR_FLITFEN; + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_ADCEN| RCC_APB2ENR_DBGMCUEN | RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM1EN;; + RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; + + GPIOA->MODER |= + (3<<GPIO_MODER_MODER0_Pos) /* PA0 - Vmeas_A to ADC */ + | (3<<GPIO_MODER_MODER1_Pos) /* PA1 - Vmeas_B to ADC */ + | (1<<GPIO_MODER_MODER2_Pos) /* PA2 - LOAD */ + | (1<<GPIO_MODER_MODER3_Pos) /* PA3 - CH0 */ + | (1<<GPIO_MODER_MODER4_Pos) /* PA4 - CH3 */ + | (0<<GPIO_MODER_MODER5_Pos) /* PA5 - TP1 */ + | (1<<GPIO_MODER_MODER6_Pos) /* PA6 - CH2 */ + | (1<<GPIO_MODER_MODER7_Pos) /* PA7 - CH1 */ + | (0<<GPIO_MODER_MODER9_Pos) /* PA9 - TP2 */ + | (0<<GPIO_MODER_MODER10_Pos);/* PA10 - TP3 */ + + /* Set shift register IO GPIO output speed */ + GPIOA->OSPEEDR |= + (2<<GPIO_OSPEEDR_OSPEEDR2_Pos) /* LOAD */ + | (2<<GPIO_OSPEEDR_OSPEEDR3_Pos) /* CH0 */ + | (2<<GPIO_OSPEEDR_OSPEEDR4_Pos) /* CH3 */ + | (2<<GPIO_OSPEEDR_OSPEEDR6_Pos) /* CH2 */ + | (2<<GPIO_OSPEEDR_OSPEEDR7_Pos); /* CH1 */ + + /* Setup CC1 and CC2. CC2 generates the LED drivers' STROBE, CC1 triggers the IRQ handler */ + TIM1->BDTR = TIM_BDTR_MOE; + TIM1->CCMR2 = (6<<TIM_CCMR2_OC4M_Pos); /* PWM Mode 1 */ + TIM1->CCER = TIM_CCER_CC4E; + TIM1->CCR4 = 1; + TIM1->DIER = TIM_DIER_UIE; + + TIM1->PSC = SystemCoreClock/500000 - 1; /* 0.5us/tick */ + TIM1->ARR = 25-1; + /* Preload all values */ + TIM1->EGR |= TIM_EGR_UG; + TIM1->CR1 = TIM_CR1_ARPE; + /* And... go! */ + TIM1->CR1 |= TIM_CR1_CEN; + + void set_outputs(uint8_t val) { + int a=!!(val&1), b=!!(val&2), c=!!(val&4), d=!!(val&8); + GPIOA->ODR &= ~(!a<<3 | !b<<7 | c<<6 | d<<4); + GPIOA->ODR |= a<<3 | b<<7 | !c<<6 | !d<<4; + } + set_outputs(0); + + adc_init(); + + uint8_t out_state = 0x01; +#define DEBOUNCE 100 + int debounce_ctr = 0; + int val_last = 0; + int ctr = 0; +#define RESET 1000 + int reset_ctr = 0; + while (42) { +#define FOO 500000 + if (reset_ctr) + reset_ctr--; + else + set_outputs(0); + + if (debounce_ctr) { + debounce_ctr--; + } else { + int val = !!(GPIOA->IDR & 1); + debounce_ctr = DEBOUNCE; + + if (val != val_last) { + if (val) + set_outputs(out_state & 0xf); + else + set_outputs(out_state >> 4); + reset_ctr = RESET; + val_last = val; + ctr++; + + if (ctr == 100) { + ctr = 0; + out_state = out_state<<1 | out_state>>7; + } + } + } + /* + for (int i=0; i<FOO; i++) ; + set_outputs(0x1); + for (int i=0; i<FOO; i++) ; + set_outputs(0x2); + for (int i=0; i<FOO; i++) ; + set_outputs(0x4); + for (int i=0; i<FOO; i++) ; + set_outputs(0x8); + */ + //for (int i=0; i<8*FOO; i++) ; + //GPIOA->ODR ^= 4; + } +} + +void NMI_Handler(void) { +} + +void HardFault_Handler(void) __attribute__((naked)); +void HardFault_Handler() { + asm volatile ("bkpt"); +} + +void SVC_Handler(void) { +} + + +void PendSV_Handler(void) { +} + +void SysTick_Handler(void) { + static int n = 0; + sys_time++; + if (n++ == 1000) { + n = 0; + sys_time_seconds++; + } +} + diff --git a/gm_platform/fw/main.elf b/gm_platform/fw/main.elf Binary files differnew file mode 100755 index 0000000..f23985f --- /dev/null +++ b/gm_platform/fw/main.elf diff --git a/gm_platform/fw/main.hex b/gm_platform/fw/main.hex new file mode 100644 index 0000000..c23d980 --- /dev/null +++ b/gm_platform/fw/main.hex @@ -0,0 +1,414 @@ +:020000040800F2
+:100000000010002095180008B1040008BD04000885
+:1000100000000000000000000000000000000000E0
+:10002000000000000000000000000000C104000803
+:100030000000000000000000CD040008D904000802
+:10004000E118000800000000E1180008E1180008AD
+:10005000E1180008E1180008E1180008E11800089C
+:1000600000000000930700085D0A0008E11800087E
+:10007000E1180008E1180008E1180008000000007D
+:10008000E11800080000000000000000E11800086E
+:1000900000000000F5030008E1180008E11800085E
+:1000A00000000000C903000800000000E11800087B
+:1000B0000000000000000000000000000000000040
+:1000C00080B582B000AF0200FB1D1A70FB1D1B78CB
+:1000D0001A001F231A40044B012191400A001A60A4
+:1000E000C046BD4602B080BD00E100E090B583B0DF
+:1000F00000AF02003960FB1D1A70FB1D1B787F2BBF
+:1001000032D92F4AFB1D1B7819000F230B40083BE7
+:100110009B0806339B00D31804331B68FA1D127822
+:10012000110003220A40D200FF2191400A00D2436D
+:100130001A4011003B689B01FF221A40FB1D1B78EF
+:10014000180003230340DB009A401D48FB1D1B7869
+:100150001C000F232340083B9B080A4306339B00E7
+:10016000C31804331A6027E0164AFB1D1B785BB2E4
+:100170009B08C0339B009B58FA1D12781100032284
+:100180000A40D200FF2191400A00D2431A401100D8
+:100190003B689B01FF221A40FB1D1B7818000323BC
+:1001A0000340DB009A400748FB1D1B785BB29B08AD
+:1001B0000A43C0339B001A50C046BD4603B090BDF1
+:1001C00000ED00E000E100E080B582B000AF7860B3
+:1001D0007B685A1E80235B049A4201D3012310E0FE
+:1001E0000A4B7A68013A5A6001235B4203211800E6
+:1001F000FFF77CFF054B00229A60044B07221A6030
+:1002000000231800BD4602B080BDC04610E000E0EB
+:1002100080B500AFC046BD4680BD80B582B000AF9E
+:100220005B4B1A685A4B802149020A431A60C04648
+:10023000574B1A6880239B021340F9D0544B5A68DD
+:10024000534B54490A405A60514B5A68504B8821CD
+:1002500049030A435A604E4B1A684D4B80214904AA
+:100260000A431A60C0464A4B1A6880239B04134015
+:10027000F9D0474B5A68464B02210A435A6000F0B6
+:1002800011FE454B1B680A21180001F08DF903008F
+:100290001800FFF799FF01235B421800FFF710FFDA
+:1002A00001235B4260211800FFF720FF384B5A6999
+:1002B000374B3A490A435A61354B9A69344B3849AE
+:1002C0000A439A61324BDA69314B02210A43DA61FF
+:1002D0009023DB051A689023DB0532490A431A6034
+:1002E0009023DB059A689023DB052F490A439A6027
+:1002F0009023DB0500221A629023DB05882252003E
+:100300005A622A4A294B12681A60294BC922920064
+:100310001A60274BE022D2005A60254B1A68244B02
+:1003200040210A431A601920FFF7CAFE4021192014
+:10033000FFF7DCFE1F4B00225A601E4B0122DA60E1
+:100340001C4B2F229A621B4B1B4ADA62194B01226B
+:100350001A601520FFF7B4FE40211520FFF7C6FEF6
+:10036000164B180000F05AF900F0BEFA144B3B602F
+:100370003B680821180000F091FB00237B6002E03D
+:100380007B6801337B607B680E4A9342F8DDEDE7C2
+:10039000001002400CF8C3FF00000020110006000E
+:1003A000015A420070A92800808A08000004004811
+:1003B0000030014000440140E703000040420F00CC
+:1003C000E41800089F86010080B500AF084B9B68C9
+:1003D0000222134009D09023DB0508229A61044BC6
+:1003E0005A68034B80218A435A60C046BD4680BD8F
+:1003F0000030014080B582B000AF284B1B6901225C
+:10040000134047D0254B1A69244B01218A431A61B6
+:10041000FB1D00221A70BB1D01221A7000233B60D5
+:100420001DE01F4B3A689200D358002B0FD01C4B95
+:100430003A689200D358591E194B3A689200D1502D
+:10044000FB1DF91DBA1D097812780A431A70BA1DEE
+:10045000BB1D1B78DB1813703B6801333B603B68A6
+:10046000072BDED90F4B1B68591C0E4A11600A2B53
+:1004700010D10C4B00221A600B4AFB1D1B78137025
+:100480000A4B5A68094B80210A435A609023DB05C6
+:1004900008229A62C046BD4602B080BD00440140B9
+:1004A000A8000020980000200C30014000300140DE
+:1004B00080B500AF00BEC046BD4680BD00BEC04690
+:1004C00080B500AF00BEC046BD4680BD80B500AF60
+:1004D00000BEC046BD4680BD80B500AF0A4B1B685C
+:1004E000591C094A11600A2B0AD1074B00221A60D5
+:1004F000064B1B685A1C054B1A60054B64229A6117
+:10050000C046BD4680BDC0469C000020940000202F
+:10051000A800002080B582B000AF0200FB1D1A7059
+:10052000FB1D1B781A001F231A40044B0121914028
+:100530000A001A60C046BD4602B080BD00E100E07E
+:1005400090B583B000AF02003960FB1D1A70FB1D2F
+:100550001B787F2B32D92F4AFB1D1B7819000F23E4
+:100560000B40083B9B0806339B00D31804331B68E1
+:10057000FA1D1278110003220A40D200FF21914097
+:100580000A00D2431A4011003B689B01FF221A4027
+:10059000FB1D1B78180003230340DB009A401D4815
+:1005A000FB1D1B781C000F232340083B9B080A43BC
+:1005B00006339B00C31804331A6027E0164AFB1D5C
+:1005C0001B785BB29B08C0339B009B58FA1D1278C6
+:1005D000110003220A40D200FF2191400A00D243B9
+:1005E0001A4011003B689B01FF221A40FB1D1B783B
+:1005F000180003230340DB009A400748FB1D1B78CB
+:100600005BB29B080A43C0339B001A50C046BD46EC
+:1006100003B090BD00ED00E000E100E080B584B0E3
+:1006200000AF78608023DB00180000F04BF8214B0E
+:10063000802212061A611F4B07225A611D4B1E4A67
+:10064000DA601C4B04229A621A4B9A68194B80217B
+:1006500009060A439A60C046164B9B68002BFBDBD9
+:10066000144B9A68134B01210A439A60114B9A6804
+:10067000104B04210A439A607B68104A934206DDBE
+:100680007B68FA21180001F019F8030000E0062346
+:10069000FB60FA6880235B029A4201DB084BFB6037
+:1006A000FB6819000C2000F03DF8C046BD4604B0C0
+:1006B00080BDC0460024014043080000DC05000066
+:1006C000FFFF000080B582B000AF7860114B124A86
+:1006D0009A60104B114ADA600E4B7A685A600D4BE3
+:1006E00000221A600B4B1A680A4B0D490A431A6024
+:1006F0000920FFF70FFF40210920FFF721FF054BDD
+:100700001A68044B01210A431A60C046BD4602B074
+:1007100080BDC0460800024040240140C8000020BF
+:10072000A205000080B582B000AF78603960154B3B
+:10073000802212025A64134BC022D201DA61114B9B
+:10074000802252011A620F4B01221A647B685A1EE2
+:100750000C4B9A623B685A1E0A4BDA62094B5A6983
+:10076000084B01210A435A61064B80221A60054B4F
+:100770001A68044B01210A431A60C046BD4602B004
+:1007800080BDC046002C014080B500AFC046BD46CC
+:1007900080BD80B500AF054B5A68044B01210A4368
+:1007A0005A60FFF7F1FFC046BD4680BD0000024021
+:1007B00080B582B000AF0200FB1D1A70FB1D1B78D4
+:1007C0001A001F231A40044B012191400A001A60AD
+:1007D000C046BD4602B080BD00E100E080B582B0F9
+:1007E00000AF0200FB1D1A70FB1D1B781A001F23AF
+:1007F0001340054901229A40130080228B50C046C5
+:10080000BD4602B080BDC04600E100E090B583B0B7
+:1008100000AF02003960FB1D1A70FB1D1B787F2B97
+:1008200032D92F4AFB1D1B7819000F230B40083BC0
+:100830009B0806339B00D31804331B68FA1D1278FB
+:10084000110003220A40D200FF2191400A00D24346
+:100850001A4011003B689B01FF221A40FB1D1B78C8
+:10086000180003230340DB009A401D48FB1D1B7842
+:100870001C000F232340083B9B080A4306339B00C0
+:10088000C31804331A6027E0164AFB1D1B785BB2BD
+:100890009B08C0339B009B58FA1D1278110003225D
+:1008A0000A40D200FF2191400A00D2431A401100B1
+:1008B0003B689B01FF221A40FB1D1B781800032395
+:1008C0000340DB009A400748FB1D1B785BB29B0886
+:1008D0000A43C0339B001A50C046BD4603B090BDCA
+:1008E00000ED00E000E100E080B500AF174B012211
+:1008F00052421A60154B00225A60144B00229A6033
+:10090000134B144A9A60124B92221A600A20FFF786
+:100910004FFF20210A20FFF779FF0F4B0F4A1A6083
+:100920000D4B3022DA600C4BC02292025A600A4B07
+:100930009A68094B80210A439A60074B1A68064B54
+:1009400001210A431A60C046BD4680BDC808002088
+:100950001C00024028380140003801402C200000D3
+:1009600080B584B000AF194BBB60BB685B687B602F
+:10097000BB689B687A689A4205D2BB689A687B68B4
+:10098000D31AFB6004E07B6880225200D31AFB601C
+:10099000BB687A681A607A68FB68D318FF221A402D
+:1009A000BB685A60BB680C331A007B68D218084BCE
+:1009B000DA60074BFA685A60054B1A68044B01214C
+:1009C0000A431A60C046BD4604B080BDC808002076
+:1009D0001C00024080B582B000AF78600A00FB1CAA
+:1009E0001A700A20FFF7FAFE7B689A687B681B681A
+:1009F0009A4205D10A20FFF7DBFE10235B4211E08B
+:100A00007B689B687A68D318FA1C12781A737B6823
+:100A10009B680133FF221A407B689A600A20FFF727
+:100A2000C7FE00231800BD4602B080BD80B582B06D
+:100A300000AF0200FB1D1A70C046FB1D1A78064B62
+:100A400011001800FFF7C6FF03001033F5D0C046B1
+:100A5000C046BD4602B080BDC808002080B500AFCA
+:100A60000B4B5A680A4B20210A435A60094B1A68FB
+:100A7000084B01218A431A60074B9A68064B5B6852
+:100A80009A4201D0FFF76CFFC046BD4680BDC0460C
+:100A9000000002401C000240C808002080B582B05F
+:100AA00000AF786039603A687B681100180000F088
+:100AB00070F8054B1B680122134001D1FFF750FF6E
+:100AC000C046BD4602B080BD1C00024080B588B063
+:100AD00000AFF860B9607A603B60BA6880235B025F
+:100AE0009A4202D23B68FE2B02D901235B424CE0C2
+:100AF0003B680233BA689A4202D201235B4244E067
+:100B00000023FB6136E0FB69002B0FD0FB69013B42
+:100B10007A68D3181B78002B08D0FB69013B7A68F0
+:100B2000D2181B23FB1812781A7019E0FB697B613D
+:100B300002E07B6901337B617A693B689A4205D2A6
+:100B40007A687B69D3181B78002BF2D17B69DAB203
+:100B5000FB69DBB2D31ADAB21B23FB1801321A701D
+:100B6000FA68FB69D3181B22BA1812781A70FB694D
+:100B70000133FB61FA693B689A42C4D9FA68FB69A0
+:100B8000D31800221A703B6802331800BD4608B023
+:100B900080BD80B586B000AF786039603B68FE2BC1
+:100BA00002D901235B4240E000237B6135E07B6991
+:100BB000002B0FD07B69013B7A68D3181B78002B80
+:100BC00008D07B69013B7A68D2181323FB1812788E
+:100BD0001A7019E07B69FB6002E0FB680133FB607F
+:100BE000FA683B689A4205D27A68FB68D3181B788A
+:100BF000002BF2D1FB68DAB27B69DBB2D31ADAB22E
+:100C00001323FB1801321A701323FB181B781800EA
+:100C1000FFF70CFF7B6901337B617A693B689A427D
+:100C2000C5D90020FFF702FF00231800BD4606B01B
+:100C300080BD80B588B000AFF860B9607A603B6075
+:100C4000BA6880235B029A4204D23A6880235B022E
+:100C50009A4202D301235B4252E03B68002B02D14F
+:100C600001235B424CE0BA683B689A4202D20123FE
+:100C70005B4245E00123FB617B681B78BB61BB697C
+:100C8000002B24D102235B423AE0BB69013BBB61EC
+:100C9000BB69002B09D17A68FB69D3181B78BB614B
+:100CA0001723FB1800221A7006E07A68FB69D21835
+:100CB0001723FB1812781A70FB69013BFA68D318E6
+:100CC0001722BA1812781A70FB690133FB61FA69AE
+:100CD0003B689A4205D27A68FB69D3181B78002BCF
+:100CE000D3D1FA693B689A4202D102235B4207E002
+:100CF000BB69012B02D003235B4201E0FB69013B8E
+:100D00001800BD4608B080BD80B582B000AF7860E5
+:100D10007B6800221A607B6800225A60C046BD468C
+:100D200002B080BD80B588B000AFF860B9607A606D
+:100D30001A00FB1C1A70FB681B68002B0ED1FB1CF1
+:100D40001B78002B54D0FB1C1A78FB685A60FB6898
+:100D50001B685A1CFB681A60002350E0FB1C1B78C0
+:100D6000002B0DD1FB685B68012B39D1FB681B6838
+:100D7000013B7B61FB681800FFF7C6FF7B693EE023
+:100D8000FB685B685A1EFB685A60FB685B68002B57
+:100D900008D1FB1C1A78FB685A601F23FB1800223D
+:100DA0001A7004E01F23FB18FA1C12781A70FB68F3
+:100DB0001B68013BBB61BA697B689A4202D302237C
+:100DC0005B421CE0BA68BB69D3181F22BA181278BC
+:100DD0001A70FB681B685A1CFB681A6000230EE03F
+:100DE000C046FB681800FFF78FFF01235B4206E057
+:100DF000C046FB681800FFF787FF03235B4218001B
+:100E0000BD4608B080BD0419000800000020940011
+:100E1000002094000020D4090020000080B500AF1D
+:100E20001A4B1A68194B01210A431A60174B5A686A
+:100E3000164B17490A405A60144B1A68134B154950
+:100E40000A401A60114B1A68104B13490A401A6085
+:100E50000E4B5A680D4B11490A405A600B4BDA6A27
+:100E60000A4B0F218A43DA62084B1A6B074B0C4975
+:100E70000A401A63054B5A6B044B01218A435A639B
+:100E8000024B00229A60C046BD4680BD0010024061
+:100E90000CB8FF08FFFFF6FEFFFFFBFFFFFFC0FFE0
+:100EA000ECFEFFFF80B584B000AF0023FB600023A1
+:100EB000BB6000237B6000233B60314B5B680C22EE
+:100EC0001340FB60FB68082B11D0FB68082B41D84E
+:100ED000FB68002B03D0FB68042B04D03AE0294BBD
+:100EE000294A1A603AE0274B274A1A6036E0244B19
+:100EF0005A68F0239B031340BB60214B5A68802340
+:100F00005B0213407B60BB689B0C0233BB601C4BD5
+:100F1000DB6A0F22134001333B607A6880235B0257
+:100F20009A420AD13968184800F03EFB03001A00C3
+:100F3000BB685A43134B1A6010E0B9680A005201AB
+:100F4000521A93019B1ADB005B181B021A000D4B0F
+:100F50001A6003E00B4B0C4A1A60C046084B5B68F2
+:100F60001B090F221340094AD35CFB60054B1A682A
+:100F7000FB68DA40034B1A60C046BD4604B080BD32
+:100F8000001002400000002000127A00EC18000857
+:100F900080B500AF044B1A68034B8021C9020A4395
+:100FA0001A60C046BD4680BD0010024080B500AF4B
+:100FB000044B1A68034B04490A401A60C046BD46F8
+:100FC00080BDC04600100240FFFFFBFF80B500AFB0
+:100FD000044B1A68034B802149020A431A60C04639
+:100FE000BD4680BD0010024080B500AF064B1A68B8
+:100FF00080239B021340054A944663445A4253415E
+:10100000DBB21800BD4680BD001002400000FEFFAC
+:1010100080B500AF044B1A68034B01210A431A60E4
+:10102000C046BD4680BDC0460010024080B500AF3E
+:10103000054B1B6802221340023B5A425341DBB26C
+:101040001800BD4680BDC0460010024080B582B089
+:1010500000AF7860064B5B68032293431900044B92
+:101060007A680A435A60C046BD4602B080BDC04699
+:101070000010024080B500AF034B5B680C221340A8
+:101080001800BD4680BDC0460010024080B582B049
+:1010900000AF7860064B5B68F02293431900044B65
+:1010A0007A680A435A60C046BD4602B080BDC04659
+:1010B0000010024080B582B000AF7860064B5B68DC
+:1010C000064A13401900044B7A680A435A60C04626
+:1010D000BD4602B080BDC04600100240FFF8FFFFD1
+:1010E00080B500AF044B1A68034B802149040A43C2
+:1010F0001A60C046BD4680BD0010024080B500AFFA
+:10110000074B1A6880239B041340FE221206944664
+:1011100063445A425341DBB21800BD4680BDC0460D
+:101120000010024080B582B000AF786039600E4B8D
+:101130005B680E4A134019007A6880235B021A40EC
+:101140003B681A43084B0A435A60074BDB6A0F227D
+:10115000934319007B680F221A40034B0A43DA625B
+:10116000C046BD4602B080BD00100240FFFFC2FF76
+:1011700080B582B000AF786039603968786800F077
+:1011800013FA03001A00064B013A5A60044B00227E
+:101190009A60034B05221A60C046BD4602B080BD6E
+:1011A00010E000E080B582B000AF7860064B1B68AD
+:1011B000012293431900044B7A680A431A60C0461F
+:1011C000BD4602B080BDC0460020024080B500AFE1
+:1011D000034B1B68012213401800BD4680BDC0466A
+:1011E0000020024080B582B000AF7860FA239A00F8
+:1011F0007B6811001800FFF7BBFFC046BD4602B078
+:1012000080BD80B584B000AF78600E4B1B68FB607A
+:10121000FB687B6801330CD07B6801337B6008E09E
+:10122000084B1A6880235B02134002D07B68013BA5
+:101230007B607B68002BF3D1C046C046BD4604B03E
+:1012400080BDC04610E000E080B582B000AF78609D
+:10125000034B7A681A60C046BD4602B080BDC046E6
+:101260000000002090B585B000AF786039600F2392
+:10127000FB1801221A700023BB6000F0D4F80300B1
+:10128000012B28D17B6801225A607B68174A19001C
+:10129000100000F0ABF80300BB60FFF7C7FE0300CF
+:1012A000012B07D0FFF7B4FEC046FFF7BFFE0300D7
+:1012B000012BFAD17B681B6819000020FFF732FF71
+:1012C0000F23FC183A68BB681100180000F0BEF844
+:1012D0000300237003E00F23FB1800221A700F2372
+:1012E000FB181B781800BD4605B090BD00127A00AF
+:1012F00090B587B000AFF860B9607A603B601723A3
+:10130000FB1801221A7000233B6100F08CF80300E7
+:10131000012B32D17A68FB681100180000F066F8E2
+:1013200003003B61FFF760FE0300012B0FD0BB6899
+:10133000012B02D1FFF72CFE01E0FFF737FEFFF78C
+:1013400045FEC046FFF750FE0300012BFAD17B6833
+:101350005B68802252021A437B681B6819001000E8
+:10136000FFF7E0FE1723FC183A683B6911001800EC
+:1013700000F06CF80300237003E01723FB18002231
+:101380001A701723FB181B781800BD4607B090BDD4
+:1013900080B584B000AF78600F217B1801221A70ED
+:1013A0000023BB607B68002B03D17B1800221A70DE
+:1013B00013E07B680C4A934201D90123BB60BB68F0
+:1013C0001800FFF7EFFEFFF701FF0200BB68934232
+:1013D00003D00F23FB1800221A700F23FB181B7871
+:1013E0001800BD4604B080BD00366E0180B584B0E3
+:1013F00000AF786039600023FB603B685B680133B5
+:101400001900786800F0D0F8030019003B681B68E9
+:101410009B0C0F22134002334B43FB60FB68180008
+:10142000BD4604B080BD80B582B000AFFB1D012277
+:101430001A70FFF763FE031E02D0FB1D00221A7014
+:10144000FB1D1B781800BD4602B080BD90B585B06D
+:1014500000AF786039600F203B1801221A7000231A
+:10146000BB602E4B1A683B681B681B090F210B40A1
+:101470002B49CB5C9A401300BB60BA687B689A42E8
+:1014800006D23C187B681800FFF782FF0300237028
+:101490000F23FB181B78012B1AD1FFF721FEC04642
+:1014A000FFF72CFE0300012BFAD13B681B681800E4
+:1014B000FFF7ECFD0220FFF7C9FDC046FFF7DAFD9C
+:1014C0000300082BFAD13B685B681800FFF7F2FDB8
+:1014D000BA687B689A4207D90F23FC187B6818000A
+:1014E000FFF756FF030023700F23FB181B78012B17
+:1014F0000CD13B681B681B090F221340084AD35CC0
+:101500001A007B68D3401800FFF79EFE0F23FB18DC
+:101510001B781800BD4605B090BDC04600000020F5
+:10152000EC18000880B500AFC046BD4680BD80B550
+:1015300086B000AFF860B9607A60FA687B68D3184B
+:101540003B61FB687B6106E0BB68DAB27B691A70BD
+:101550007B6901337B617A693B699A42F4D3FB680A
+:101560001800BD4606B080BD80B584B000AF78607D
+:101570007B68FB60C0467B685A1C7A601B78002B36
+:10158000F9D17A68FB68D31A013B1800BD4604B054
+:1015900080BD80B582B000AF0200FB1D1A70C0464E
+:1015A000BD4602B080BD0000002243088B4274D3C8
+:1015B00003098B425FD3030A8B4244D3030B8B4254
+:1015C00028D3030C8B420DD3FF22090212BA030C5D
+:1015D0008B4202D31212090265D0030B8B4219D33E
+:1015E00000E0090AC30B8B4201D3CB03C01A52415E
+:1015F000830B8B4201D38B03C01A5241430B8B42A6
+:1016000001D34B03C01A5241030B8B4201D30B038E
+:10161000C01A5241C30A8B4201D3CB02C01A5241B5
+:10162000830A8B4201D38B02C01A5241430A8B4278
+:1016300001D34B02C01A5241030A8B4201D30B0261
+:10164000C01A5241CDD2C3098B4201D3CB01C01A7B
+:10165000524183098B4201D38B01C01A5241430985
+:101660008B4201D34B01C01A524103098B4201D373
+:101670000B01C01A5241C3088B4201D3CB00C01AE0
+:10168000524183088B4201D38B00C01A5241430858
+:101690008B4201D34B00C01A5241411A00D201467D
+:1016A000524110467047FFE701B5002000F0F0F806
+:1016B00002BDC0460029F7D076E7704703460B43CA
+:1016C0007FD4002243088B4274D303098B425FD33B
+:1016D000030A8B4244D3030B8B4228D3030C8B4267
+:1016E0000DD3FF22090212BA030C8B4202D312124D
+:1016F000090265D0030B8B4219D300E0090AC30B22
+:101700008B4201D3CB03C01A5241830B8B4201D3CE
+:101710008B03C01A5241430B8B4201D34B03C01AB7
+:101720005241030B8B4201D30B03C01A5241C30A2F
+:101730008B4201D3CB02C01A5241830A8B4201D3A0
+:101740008B02C01A5241430A8B4201D34B02C01A8A
+:101750005241030A8B4201D30B02C01A5241CDD22F
+:10176000C3098B4201D3CB01C01A524183098B427A
+:1017700001D38B01C01A524143098B4201D34B0163
+:10178000C01A524103098B4201D30B01C01A5241C6
+:10179000C3088B4201D3CB00C01A524183088B424D
+:1017A00001D38B00C01A524143088B4201D34B0036
+:1017B000C01A5241411A00D20146524110467047A8
+:1017C0005DE0CA0F00D04942031000D340425340AD
+:1017D00000229C4603098B422DD3030A8B4212D36D
+:1017E000FC22890112BA030A8B420CD3890192119F
+:1017F0008B4208D3890192118B4204D389013AD0DC
+:10180000921100E08909C3098B4201D3CB01C01AB0
+:10181000524183098B4201D38B01C01A52414309C3
+:101820008B4201D34B01C01A524103098B4201D3B1
+:101830000B01C01A5241C3088B4201D3CB00C01A1E
+:10184000524183088B4201D38B00C01A5241D9D236
+:1018500043088B4201D34B00C01A5241411A00D2B7
+:101860000146634652415B10104601D34042002BB3
+:1018700000D54942704763465B1000D3404201B532
+:10188000002000F005F802BD0029F8D016E77047E7
+:101890007047C0460C488546002103E00B4B5B585F
+:1018A000435004310A480B4B42189A42F6D30A4A75
+:1018B00002E0002313600432084B9A42F9D3FFF789
+:1018C000ADFAFEF7AAFCFEE700100020041900089C
+:1018D000000000209400002094000020D409002083
+:1018E000FEE70000464F4F4241520A000000000050
+:1018F00000000000010203040607080900000000C0
+:0419000001020304D9
+:1019040000127A000004004000200040002800403B
+:10191400002C0040003000400054004000700040A3
+:101924000000014000040140002401400827014058
+:1019340008270140002C01400030014000380140DC
+:1019440000440140004801400058014000000240AA
+:10195400080002401C0002403000024044000240E3
+:10196400580002400020024000F8FF1F001002400F
+:10197400003002400000004800040048000800480D
+:10198400000C00480014004800ED00E010E000E006
+:0419940000E100E08E
+:040000050800189542
+:00000001FF
diff --git a/gm_platform/fw/main.lst b/gm_platform/fw/main.lst new file mode 100644 index 0000000..5be6e7e --- /dev/null +++ b/gm_platform/fw/main.lst @@ -0,0 +1,4459 @@ + +main.elf: file format elf32-littlearm + +SYMBOL TABLE: +08000000 l d .isr_vector 00000000 .isr_vector +080000c0 l d .text 00000000 .text +20000000 l d .data 00000000 .data +20000094 l d .bss 00000000 .bss +00000000 l d .comment 00000000 .comment +00000000 l d .ARM.attributes 00000000 .ARM.attributes +00000000 l d .debug_aranges 00000000 .debug_aranges +00000000 l d .debug_info 00000000 .debug_info +00000000 l d .debug_abbrev 00000000 .debug_abbrev +00000000 l d .debug_line 00000000 .debug_line +00000000 l d .debug_frame 00000000 .debug_frame +00000000 l d .debug_str 00000000 .debug_str +00000000 l d .debug_ranges 00000000 .debug_ranges +00000000 l df *ABS* 00000000 /tmp/ccTaPb5k.o +080018a4 l .text 00000000 LoopCopyDataInit +0800189c l .text 00000000 CopyDataInit +080018b8 l .text 00000000 LoopFillZerobss +080018b2 l .text 00000000 FillZerobss +080018c6 l .text 00000000 LoopForever +080018e0 l .text 00000000 Infinite_Loop +00000000 l df *ABS* 00000000 main.c +080000c0 l F .text 0000002c NVIC_EnableIRQ +080000ec l F .text 000000dc NVIC_SetPriority +080001c8 l F .text 00000048 SysTick_Config +20000098 l .bss 00000004 leds_update_counter.5785 +2000009c l .bss 00000004 n.5808 +00000000 l df *ABS* 00000000 adc.c +08000514 l F .text 0000002c NVIC_EnableIRQ +08000540 l F .text 000000dc NVIC_SetPriority +080006c4 l F .text 00000060 adc_dma_init +08000724 l F .text 00000064 adc_timer_init +08000788 l F .text 0000000a gdb_dump +00000000 l df *ABS* 00000000 serial.c +080007b0 l F .text 0000002c NVIC_EnableIRQ +080007dc l F .text 00000030 NVIC_DisableIRQ +0800080c l F .text 000000dc NVIC_SetPriority +08000960 l F .text 00000074 usart_schedule_dma +00000000 l df *ABS* 00000000 cobs.c +00000000 l df *ABS* 00000000 system_stm32f0xx.c +00000000 l df *ABS* 00000000 stm32f0xx_ll_utils.c +08000f90 l F .text 0000001c LL_RCC_HSE_EnableBypass +08000fac l F .text 00000020 LL_RCC_HSE_DisableBypass +08000fcc l F .text 0000001c LL_RCC_HSE_Enable +08000fe8 l F .text 00000028 LL_RCC_HSE_IsReady +08001010 l F .text 0000001c LL_RCC_HSI_Enable +0800102c l F .text 00000020 LL_RCC_HSI_IsReady +0800104c l F .text 00000028 LL_RCC_SetSysClkSource +08001074 l F .text 00000018 LL_RCC_GetSysClkSource +0800108c l F .text 00000028 LL_RCC_SetAHBPrescaler +080010b4 l F .text 0000002c LL_RCC_SetAPB1Prescaler +080010e0 l F .text 0000001c LL_RCC_PLL_Enable +080010fc l F .text 00000028 LL_RCC_PLL_IsReady +08001124 l F .text 0000004c LL_RCC_PLL_ConfigDomain_SYS +08001170 l F .text 00000034 LL_InitTick +080011a4 l F .text 00000028 LL_FLASH_SetLatency +080011cc l F .text 00000018 LL_FLASH_GetLatency +08001426 l F .text 00000026 UTILS_PLL_IsBusy +080013ec l F .text 0000003a UTILS_GetPLLOutputFrequency +0800144c l F .text 000000d8 UTILS_EnablePLLAndSwitchSystem +08001390 l F .text 0000005c UTILS_SetFlashLatency +00000000 l df *ABS* 00000000 base.c +00000000 l df *ABS* 00000000 cmsis_exports.c +00000000 l df *ABS* 00000000 _udivsi3.o +080015a8 l .text 00000000 .udivsi3_skip_div0_test +00000000 l df *ABS* 00000000 _divsi3.o +080016bc l .text 00000000 .divsi3_skip_div0_test +00000000 l df *ABS* 00000000 _dvmd_tls.o +080018fc g O .text 00000008 APBPrescTable +20000044 g O .data 00000004 tim17 +2000007c g O .data 00000004 gpioc +20000088 g O .data 00000004 scb +08001202 g F .text 00000046 LL_mDelay +08000a9c g F .text 00000030 usart_send_packet +080018e0 w F .text 00000002 TIM1_CC_IRQHandler +08001524 g F .text 0000000a __sinit +080004bc g F .text 00000004 HardFault_Handler +2000006c g O .data 00000004 rcc +080004d8 g F .text 0000003c SysTick_Handler +08001904 g .text 00000000 _sidata +080004cc g F .text 0000000c PendSV_Handler +20000020 g O .data 00000004 syscfg +080004b0 g F .text 0000000c NMI_Handler +200009d4 g .bss 00000000 __exidx_end +08001264 g F .text 0000008c LL_PLL_ConfigSystemClock_HSI +080018e0 w F .text 00000002 I2C1_IRQHandler +08001248 g F .text 0000001c LL_SetSystemCoreClock +200000a0 g O .bss 00000004 __errno +20000008 g O .data 00000004 tim14 +20000048 g O .data 00000004 dbgmcu +2000003c g O .data 00000004 usart1 +08001904 g .text 00000000 _etext +20000094 g .bss 00000000 _sbss +08000c32 g F .text 000000d6 cobs_decode +200008c8 g O .bss 0000010c usart_tx_buf +20000094 g O .bss 00000004 sys_time_seconds +20000000 g O .data 00000004 SystemCoreClock +2000001c g O .data 00000004 pwr +080015a8 g F .text 0000010a .hidden __udivsi3 +08001592 g F .text 00000014 __assert_func +20000000 g .data 00000000 _sdata +080003c8 g F .text 0000002c SPI1_IRQHandler +20000060 g O .data 00000004 dma1_channel5 +20000058 g O .data 00000004 dma1_channel3 +200009d4 g .bss 00000000 __exidx_start +080011e4 g F .text 0000001e LL_Init1msTick +20000054 g O .data 00000004 dma1_channel2 +080018e0 w F .text 00000002 EXTI2_3_IRQHandler +080018e0 w F .text 00000002 ADC1_IRQHandler +08000d24 g F .text 000000e2 cobs_decode_incremental +2000004c g O .data 00000004 dma1 +080018e0 w F .text 00000002 TIM17_IRQHandler +080018e0 w F .text 00000002 RTC_IRQHandler +200009d4 g .bss 00000000 _ebss +2000002c g O .data 00000004 adc1_common +08001894 w F .text 00000034 Reset_Handler +20000070 g O .data 00000004 crc +20000024 g O .data 00000004 exti +08000210 g F .text 0000000a update_leds +20000028 g O .data 00000004 adc1 +080016bc g F .text 00000000 .hidden __aeabi_idiv +08000acc g F .text 000000c6 cobs_encode +200000a8 g O .bss 00000020 leds +20000074 g O .data 00000004 gpioa +080003f4 g F .text 000000bc TIM16_IRQHandler +080018e0 w F .text 00000002 TIM3_IRQHandler +080018e0 w F .text 00000002 EXTI4_15_IRQHandler +080018e0 w F .text 00000002 RCC_IRQHandler +20000094 g .bss 00000000 _bss +08000792 g F .text 0000001e DMA1_Channel1_IRQHandler +080018e0 g .text 00000002 Default_Handler +080018ec g O .text 00000010 AHBPrescTable +08000b92 g F .text 000000a0 cobs_encode_usart +20000010 g O .data 00000004 wwdg +080018e0 w F .text 00000002 TIM14_IRQHandler +080018e0 w F .text 00000002 DMA1_Channel4_5_IRQHandler +20000030 g O .data 00000004 adc +08000a2c g F .text 00000030 usart_putc +080018e0 w F .text 00000002 EXTI0_1_IRQHandler +08001890 w F .text 00000002 .hidden __aeabi_ldiv0 +20000004 g O .data 00000004 tim3 +2000000c g O .data 00000004 rtc +080008e8 g F .text 00000078 usart_dma_init +0800152e g F .text 0000003a memset +0800021a g F .text 000001ae main +20000064 g O .data 00000004 flash +080015a8 g F .text 00000000 .hidden __aeabi_uidiv +080004c0 g F .text 0000000c SVC_Handler +20000018 g O .data 00000004 i2c1 +20000050 g O .data 00000004 dma1_channel1 +080016bc g F .text 000001cc .hidden __divsi3 +20000090 g O .data 00000004 nvic +08000e1c g F .text 00000088 SystemInit +200000a4 g O .bss 00000004 _impure_ptr +080018e0 w F .text 00000002 WWDG_IRQHandler +20000000 g .data 00000000 _data +20000084 g O .data 00000004 gpiof +08000a5c g F .text 00000040 DMA1_Channel2_3_IRQHandler +200000c8 g O .bss 00000800 adc_buf +20000080 g O .data 00000004 gpiod +20001000 g *ABS* 00000000 _estack +080016b4 g F .text 00000008 .hidden __aeabi_uidivmod +20000068 g O .data 00000004 ob +20000094 g .data 00000000 _edata +20000038 g O .data 00000004 spi1 +080009d4 g F .text 00000058 usart_dma_fifo_push +2000005c g O .data 00000004 dma1_channel4 +08000000 g O .isr_vector 00000000 g_pfnVectors +08000ea4 g F .text 000000ec SystemCoreClockUpdate +080012f0 g F .text 000000a0 LL_PLL_ConfigSystemClock_HSE +08001890 w F .text 00000002 .hidden __aeabi_idiv0 +20000014 g O .data 00000004 iwdg +080018e0 w F .text 00000002 FLASH_IRQHandler +08000d08 g F .text 0000001c cobs_decode_incremental_initialize +080018e0 w F .text 00000002 USART1_IRQHandler +0800061c g F .text 000000a8 adc_configure_scope_mode +08001568 g F .text 0000002a strlen +080018e0 w F .text 00000002 TIM1_BRK_UP_TRG_COM_IRQHandler +20000078 g O .data 00000004 gpiob +20000034 g O .data 00000004 tim1 +2000008c g O .data 00000004 systick +08001888 g F .text 00000008 .hidden __aeabi_idivmod +20000040 g O .data 00000004 tim16 + + + +Disassembly of section .text: + +080000c0 <NVIC_EnableIRQ>: + \brief Enable External Interrupt + \details Enables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +{ + 80000c0: b580 push {r7, lr} + 80000c2: b082 sub sp, #8 + 80000c4: af00 add r7, sp, #0 + 80000c6: 0002 movs r2, r0 + 80000c8: 1dfb adds r3, r7, #7 + 80000ca: 701a strb r2, [r3, #0] + NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + 80000cc: 1dfb adds r3, r7, #7 + 80000ce: 781b ldrb r3, [r3, #0] + 80000d0: 001a movs r2, r3 + 80000d2: 231f movs r3, #31 + 80000d4: 401a ands r2, r3 + 80000d6: 4b04 ldr r3, [pc, #16] ; (80000e8 <NVIC_EnableIRQ+0x28>) + 80000d8: 2101 movs r1, #1 + 80000da: 4091 lsls r1, r2 + 80000dc: 000a movs r2, r1 + 80000de: 601a str r2, [r3, #0] +} + 80000e0: 46c0 nop ; (mov r8, r8) + 80000e2: 46bd mov sp, r7 + 80000e4: b002 add sp, #8 + 80000e6: bd80 pop {r7, pc} + 80000e8: e000e100 .word 0xe000e100 + +080000ec <NVIC_SetPriority>: + \note The priority cannot be set for every core interrupt. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + */ +__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + 80000ec: b590 push {r4, r7, lr} + 80000ee: b083 sub sp, #12 + 80000f0: af00 add r7, sp, #0 + 80000f2: 0002 movs r2, r0 + 80000f4: 6039 str r1, [r7, #0] + 80000f6: 1dfb adds r3, r7, #7 + 80000f8: 701a strb r2, [r3, #0] + if ((int32_t)(IRQn) < 0) + 80000fa: 1dfb adds r3, r7, #7 + 80000fc: 781b ldrb r3, [r3, #0] + 80000fe: 2b7f cmp r3, #127 ; 0x7f + 8000100: d932 bls.n 8000168 <NVIC_SetPriority+0x7c> + { + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + 8000102: 4a2f ldr r2, [pc, #188] ; (80001c0 <NVIC_SetPriority+0xd4>) + 8000104: 1dfb adds r3, r7, #7 + 8000106: 781b ldrb r3, [r3, #0] + 8000108: 0019 movs r1, r3 + 800010a: 230f movs r3, #15 + 800010c: 400b ands r3, r1 + 800010e: 3b08 subs r3, #8 + 8000110: 089b lsrs r3, r3, #2 + 8000112: 3306 adds r3, #6 + 8000114: 009b lsls r3, r3, #2 + 8000116: 18d3 adds r3, r2, r3 + 8000118: 3304 adds r3, #4 + 800011a: 681b ldr r3, [r3, #0] + 800011c: 1dfa adds r2, r7, #7 + 800011e: 7812 ldrb r2, [r2, #0] + 8000120: 0011 movs r1, r2 + 8000122: 2203 movs r2, #3 + 8000124: 400a ands r2, r1 + 8000126: 00d2 lsls r2, r2, #3 + 8000128: 21ff movs r1, #255 ; 0xff + 800012a: 4091 lsls r1, r2 + 800012c: 000a movs r2, r1 + 800012e: 43d2 mvns r2, r2 + 8000130: 401a ands r2, r3 + 8000132: 0011 movs r1, r2 + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + 8000134: 683b ldr r3, [r7, #0] + 8000136: 019b lsls r3, r3, #6 + 8000138: 22ff movs r2, #255 ; 0xff + 800013a: 401a ands r2, r3 + 800013c: 1dfb adds r3, r7, #7 + 800013e: 781b ldrb r3, [r3, #0] + 8000140: 0018 movs r0, r3 + 8000142: 2303 movs r3, #3 + 8000144: 4003 ands r3, r0 + 8000146: 00db lsls r3, r3, #3 + 8000148: 409a lsls r2, r3 + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + 800014a: 481d ldr r0, [pc, #116] ; (80001c0 <NVIC_SetPriority+0xd4>) + 800014c: 1dfb adds r3, r7, #7 + 800014e: 781b ldrb r3, [r3, #0] + 8000150: 001c movs r4, r3 + 8000152: 230f movs r3, #15 + 8000154: 4023 ands r3, r4 + 8000156: 3b08 subs r3, #8 + 8000158: 089b lsrs r3, r3, #2 + 800015a: 430a orrs r2, r1 + 800015c: 3306 adds r3, #6 + 800015e: 009b lsls r3, r3, #2 + 8000160: 18c3 adds r3, r0, r3 + 8000162: 3304 adds r3, #4 + 8000164: 601a str r2, [r3, #0] + else + { + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } +} + 8000166: e027 b.n 80001b8 <NVIC_SetPriority+0xcc> + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + 8000168: 4a16 ldr r2, [pc, #88] ; (80001c4 <NVIC_SetPriority+0xd8>) + 800016a: 1dfb adds r3, r7, #7 + 800016c: 781b ldrb r3, [r3, #0] + 800016e: b25b sxtb r3, r3 + 8000170: 089b lsrs r3, r3, #2 + 8000172: 33c0 adds r3, #192 ; 0xc0 + 8000174: 009b lsls r3, r3, #2 + 8000176: 589b ldr r3, [r3, r2] + 8000178: 1dfa adds r2, r7, #7 + 800017a: 7812 ldrb r2, [r2, #0] + 800017c: 0011 movs r1, r2 + 800017e: 2203 movs r2, #3 + 8000180: 400a ands r2, r1 + 8000182: 00d2 lsls r2, r2, #3 + 8000184: 21ff movs r1, #255 ; 0xff + 8000186: 4091 lsls r1, r2 + 8000188: 000a movs r2, r1 + 800018a: 43d2 mvns r2, r2 + 800018c: 401a ands r2, r3 + 800018e: 0011 movs r1, r2 + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + 8000190: 683b ldr r3, [r7, #0] + 8000192: 019b lsls r3, r3, #6 + 8000194: 22ff movs r2, #255 ; 0xff + 8000196: 401a ands r2, r3 + 8000198: 1dfb adds r3, r7, #7 + 800019a: 781b ldrb r3, [r3, #0] + 800019c: 0018 movs r0, r3 + 800019e: 2303 movs r3, #3 + 80001a0: 4003 ands r3, r0 + 80001a2: 00db lsls r3, r3, #3 + 80001a4: 409a lsls r2, r3 + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + 80001a6: 4807 ldr r0, [pc, #28] ; (80001c4 <NVIC_SetPriority+0xd8>) + 80001a8: 1dfb adds r3, r7, #7 + 80001aa: 781b ldrb r3, [r3, #0] + 80001ac: b25b sxtb r3, r3 + 80001ae: 089b lsrs r3, r3, #2 + 80001b0: 430a orrs r2, r1 + 80001b2: 33c0 adds r3, #192 ; 0xc0 + 80001b4: 009b lsls r3, r3, #2 + 80001b6: 501a str r2, [r3, r0] +} + 80001b8: 46c0 nop ; (mov r8, r8) + 80001ba: 46bd mov sp, r7 + 80001bc: b003 add sp, #12 + 80001be: bd90 pop {r4, r7, pc} + 80001c0: e000ed00 .word 0xe000ed00 + 80001c4: e000e100 .word 0xe000e100 + +080001c8 <SysTick_Config>: + \note When the variable <b>__Vendor_SysTickConfig</b> is set to 1, then the + function <b>SysTick_Config</b> is not included. In this case, the file <b><i>device</i>.h</b> + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + 80001c8: b580 push {r7, lr} + 80001ca: b082 sub sp, #8 + 80001cc: af00 add r7, sp, #0 + 80001ce: 6078 str r0, [r7, #4] + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + 80001d0: 687b ldr r3, [r7, #4] + 80001d2: 1e5a subs r2, r3, #1 + 80001d4: 2380 movs r3, #128 ; 0x80 + 80001d6: 045b lsls r3, r3, #17 + 80001d8: 429a cmp r2, r3 + 80001da: d301 bcc.n 80001e0 <SysTick_Config+0x18> + { + return (1UL); /* Reload value impossible */ + 80001dc: 2301 movs r3, #1 + 80001de: e010 b.n 8000202 <SysTick_Config+0x3a> + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + 80001e0: 4b0a ldr r3, [pc, #40] ; (800020c <SysTick_Config+0x44>) + 80001e2: 687a ldr r2, [r7, #4] + 80001e4: 3a01 subs r2, #1 + 80001e6: 605a str r2, [r3, #4] + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + 80001e8: 2301 movs r3, #1 + 80001ea: 425b negs r3, r3 + 80001ec: 2103 movs r1, #3 + 80001ee: 0018 movs r0, r3 + 80001f0: f7ff ff7c bl 80000ec <NVIC_SetPriority> + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + 80001f4: 4b05 ldr r3, [pc, #20] ; (800020c <SysTick_Config+0x44>) + 80001f6: 2200 movs r2, #0 + 80001f8: 609a str r2, [r3, #8] + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + 80001fa: 4b04 ldr r3, [pc, #16] ; (800020c <SysTick_Config+0x44>) + 80001fc: 2207 movs r2, #7 + 80001fe: 601a str r2, [r3, #0] + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ + 8000200: 2300 movs r3, #0 +} + 8000202: 0018 movs r0, r3 + 8000204: 46bd mov sp, r7 + 8000206: b002 add sp, #8 + 8000208: bd80 pop {r7, pc} + 800020a: 46c0 nop ; (mov r8, r8) + 800020c: e000e010 .word 0xe000e010 + +08000210 <update_leds>: +#include "serial.h" + + +volatile unsigned int sys_time_seconds = 0; + +void update_leds() { + 8000210: b580 push {r7, lr} + 8000212: af00 add r7, sp, #0 + +} + 8000214: 46c0 nop ; (mov r8, r8) + 8000216: 46bd mov sp, r7 + 8000218: bd80 pop {r7, pc} + +0800021a <main>: + unsigned int usb, ocxo, error, _nc1, _nc2, _nc3, pps, sd_card; + }; + unsigned int arr[0]; +} leds; + +int main(void) { + 800021a: b580 push {r7, lr} + 800021c: b082 sub sp, #8 + 800021e: af00 add r7, sp, #0 + RCC->CR |= RCC_CR_HSEON; + 8000220: 4b5b ldr r3, [pc, #364] ; (8000390 <main+0x176>) + 8000222: 681a ldr r2, [r3, #0] + 8000224: 4b5a ldr r3, [pc, #360] ; (8000390 <main+0x176>) + 8000226: 2180 movs r1, #128 ; 0x80 + 8000228: 0249 lsls r1, r1, #9 + 800022a: 430a orrs r2, r1 + 800022c: 601a str r2, [r3, #0] + while (!(RCC->CR&RCC_CR_HSERDY)); + 800022e: 46c0 nop ; (mov r8, r8) + 8000230: 4b57 ldr r3, [pc, #348] ; (8000390 <main+0x176>) + 8000232: 681a ldr r2, [r3, #0] + 8000234: 2380 movs r3, #128 ; 0x80 + 8000236: 029b lsls r3, r3, #10 + 8000238: 4013 ands r3, r2 + 800023a: d0f9 beq.n 8000230 <main+0x16> + RCC->CFGR &= ~RCC_CFGR_PLLMUL_Msk & ~RCC_CFGR_SW_Msk & ~RCC_CFGR_PPRE_Msk & ~RCC_CFGR_HPRE_Msk; + 800023c: 4b54 ldr r3, [pc, #336] ; (8000390 <main+0x176>) + 800023e: 685a ldr r2, [r3, #4] + 8000240: 4b53 ldr r3, [pc, #332] ; (8000390 <main+0x176>) + 8000242: 4954 ldr r1, [pc, #336] ; (8000394 <main+0x17a>) + 8000244: 400a ands r2, r1 + 8000246: 605a str r2, [r3, #4] + RCC->CFGR |= ((6-2)<<RCC_CFGR_PLLMUL_Pos) | RCC_CFGR_PLLSRC_HSE_PREDIV; /* PLL x6 -> 48.0MHz */ + 8000248: 4b51 ldr r3, [pc, #324] ; (8000390 <main+0x176>) + 800024a: 685a ldr r2, [r3, #4] + 800024c: 4b50 ldr r3, [pc, #320] ; (8000390 <main+0x176>) + 800024e: 2188 movs r1, #136 ; 0x88 + 8000250: 0349 lsls r1, r1, #13 + 8000252: 430a orrs r2, r1 + 8000254: 605a str r2, [r3, #4] + RCC->CR |= RCC_CR_PLLON; + 8000256: 4b4e ldr r3, [pc, #312] ; (8000390 <main+0x176>) + 8000258: 681a ldr r2, [r3, #0] + 800025a: 4b4d ldr r3, [pc, #308] ; (8000390 <main+0x176>) + 800025c: 2180 movs r1, #128 ; 0x80 + 800025e: 0449 lsls r1, r1, #17 + 8000260: 430a orrs r2, r1 + 8000262: 601a str r2, [r3, #0] + while (!(RCC->CR&RCC_CR_PLLRDY)); + 8000264: 46c0 nop ; (mov r8, r8) + 8000266: 4b4a ldr r3, [pc, #296] ; (8000390 <main+0x176>) + 8000268: 681a ldr r2, [r3, #0] + 800026a: 2380 movs r3, #128 ; 0x80 + 800026c: 049b lsls r3, r3, #18 + 800026e: 4013 ands r3, r2 + 8000270: d0f9 beq.n 8000266 <main+0x4c> + RCC->CFGR |= (2<<RCC_CFGR_SW_Pos); + 8000272: 4b47 ldr r3, [pc, #284] ; (8000390 <main+0x176>) + 8000274: 685a ldr r2, [r3, #4] + 8000276: 4b46 ldr r3, [pc, #280] ; (8000390 <main+0x176>) + 8000278: 2102 movs r1, #2 + 800027a: 430a orrs r2, r1 + 800027c: 605a str r2, [r3, #4] + SystemCoreClockUpdate(); + 800027e: f000 fe11 bl 8000ea4 <SystemCoreClockUpdate> + SysTick_Config(SystemCoreClock/10); /* 100ms interval */ + 8000282: 4b45 ldr r3, [pc, #276] ; (8000398 <main+0x17e>) + 8000284: 681b ldr r3, [r3, #0] + 8000286: 210a movs r1, #10 + 8000288: 0018 movs r0, r3 + 800028a: f001 f98d bl 80015a8 <__udivsi3> + 800028e: 0003 movs r3, r0 + 8000290: 0018 movs r0, r3 + 8000292: f7ff ff99 bl 80001c8 <SysTick_Config> + NVIC_EnableIRQ(SysTick_IRQn); + 8000296: 2301 movs r3, #1 + 8000298: 425b negs r3, r3 + 800029a: 0018 movs r0, r3 + 800029c: f7ff ff10 bl 80000c0 <NVIC_EnableIRQ> + NVIC_SetPriority(SysTick_IRQn, 3<<5); + 80002a0: 2301 movs r3, #1 + 80002a2: 425b negs r3, r3 + 80002a4: 2160 movs r1, #96 ; 0x60 + 80002a6: 0018 movs r0, r3 + 80002a8: f7ff ff20 bl 80000ec <NVIC_SetPriority> + + /* Turn on lots of neat things */ + RCC->AHBENR |= RCC_AHBENR_DMAEN | RCC_AHBENR_GPIOAEN | RCC_AHBENR_GPIOBEN | RCC_AHBENR_FLITFEN; + 80002ac: 4b38 ldr r3, [pc, #224] ; (8000390 <main+0x176>) + 80002ae: 695a ldr r2, [r3, #20] + 80002b0: 4b37 ldr r3, [pc, #220] ; (8000390 <main+0x176>) + 80002b2: 493a ldr r1, [pc, #232] ; (800039c <main+0x182>) + 80002b4: 430a orrs r2, r1 + 80002b6: 615a str r2, [r3, #20] + RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN | RCC_APB2ENR_ADCEN | RCC_APB2ENR_SPI1EN | RCC_APB2ENR_DBGMCUEN |\ + 80002b8: 4b35 ldr r3, [pc, #212] ; (8000390 <main+0x176>) + 80002ba: 699a ldr r2, [r3, #24] + 80002bc: 4b34 ldr r3, [pc, #208] ; (8000390 <main+0x176>) + 80002be: 4938 ldr r1, [pc, #224] ; (80003a0 <main+0x186>) + 80002c0: 430a orrs r2, r1 + 80002c2: 619a str r2, [r3, #24] + RCC_APB2ENR_TIM1EN | RCC_APB2ENR_TIM16EN | RCC_APB2ENR_USART1EN; + RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; + 80002c4: 4b32 ldr r3, [pc, #200] ; (8000390 <main+0x176>) + 80002c6: 69da ldr r2, [r3, #28] + 80002c8: 4b31 ldr r3, [pc, #196] ; (8000390 <main+0x176>) + 80002ca: 2102 movs r1, #2 + 80002cc: 430a orrs r2, r1 + 80002ce: 61da str r2, [r3, #28] + + GPIOA->MODER |= + 80002d0: 2390 movs r3, #144 ; 0x90 + 80002d2: 05db lsls r3, r3, #23 + 80002d4: 681a ldr r2, [r3, #0] + 80002d6: 2390 movs r3, #144 ; 0x90 + 80002d8: 05db lsls r3, r3, #23 + 80002da: 4932 ldr r1, [pc, #200] ; (80003a4 <main+0x18a>) + 80002dc: 430a orrs r2, r1 + 80002de: 601a str r2, [r3, #0] + | (2<<GPIO_MODER_MODER7_Pos) /* PA7 - MOSI */ + | (2<<GPIO_MODER_MODER9_Pos) /* PA9 - HOST_RX */ + | (2<<GPIO_MODER_MODER10_Pos);/* PA10 - HOST_TX */ + + /* Set shift register IO GPIO output speed */ + GPIOA->OSPEEDR |= + 80002e0: 2390 movs r3, #144 ; 0x90 + 80002e2: 05db lsls r3, r3, #23 + 80002e4: 689a ldr r2, [r3, #8] + 80002e6: 2390 movs r3, #144 ; 0x90 + 80002e8: 05db lsls r3, r3, #23 + 80002ea: 492f ldr r1, [pc, #188] ; (80003a8 <main+0x18e>) + 80002ec: 430a orrs r2, r1 + 80002ee: 609a str r2, [r3, #8] + | (2<<GPIO_OSPEEDR_OSPEEDR4_Pos) /* SD_CS */ + | (2<<GPIO_OSPEEDR_OSPEEDR5_Pos) /* SCK */ + | (2<<GPIO_OSPEEDR_OSPEEDR7_Pos) /* MOSI */ + | (2<<GPIO_OSPEEDR_OSPEEDR9_Pos); /* HOST_RX */ + + GPIOA->AFR[0] = (0<<GPIO_AFRL_AFRL5_Pos) | (0<<GPIO_AFRL_AFRL6_Pos) | (0<<GPIO_AFRL_AFRL7_Pos); + 80002f0: 2390 movs r3, #144 ; 0x90 + 80002f2: 05db lsls r3, r3, #23 + 80002f4: 2200 movs r2, #0 + 80002f6: 621a str r2, [r3, #32] + GPIOA->AFR[1] = (1<<8) | (1<<4); + 80002f8: 2390 movs r3, #144 ; 0x90 + 80002fa: 05db lsls r3, r3, #23 + 80002fc: 2288 movs r2, #136 ; 0x88 + 80002fe: 0052 lsls r2, r2, #1 + 8000300: 625a str r2, [r3, #36] ; 0x24 + + GPIOB->MODER |= + 8000302: 4a2a ldr r2, [pc, #168] ; (80003ac <main+0x192>) + 8000304: 4b29 ldr r3, [pc, #164] ; (80003ac <main+0x192>) + 8000306: 6812 ldr r2, [r2, #0] + 8000308: 601a str r2, [r3, #0] + (0<<GPIO_MODER_MODER1_Pos); /* PB0 - LINE_POL */ + + SPI1->CR1 = + 800030a: 4b29 ldr r3, [pc, #164] ; (80003b0 <main+0x196>) + 800030c: 22c9 movs r2, #201 ; 0xc9 + 800030e: 0092 lsls r2, r2, #2 + 8000310: 601a str r2, [r3, #0] + SPI_CR1_SSM + | SPI_CR1_SSI + | (4<<SPI_CR1_BR_Pos) /* /32 ~1.5MHz */ + | SPI_CR1_MSTR; + SPI1->CR2 = (7<<SPI_CR2_DS_Pos); + 8000312: 4b27 ldr r3, [pc, #156] ; (80003b0 <main+0x196>) + 8000314: 22e0 movs r2, #224 ; 0xe0 + 8000316: 00d2 lsls r2, r2, #3 + 8000318: 605a str r2, [r3, #4] + SPI1->CR1 |= SPI_CR1_SPE; + 800031a: 4b25 ldr r3, [pc, #148] ; (80003b0 <main+0x196>) + 800031c: 681a ldr r2, [r3, #0] + 800031e: 4b24 ldr r3, [pc, #144] ; (80003b0 <main+0x196>) + 8000320: 2140 movs r1, #64 ; 0x40 + 8000322: 430a orrs r2, r1 + 8000324: 601a str r2, [r3, #0] + + NVIC_EnableIRQ(SPI1_IRQn); + 8000326: 2019 movs r0, #25 + 8000328: f7ff feca bl 80000c0 <NVIC_EnableIRQ> + NVIC_SetPriority(SPI1_IRQn, 2<<5); + 800032c: 2140 movs r1, #64 ; 0x40 + 800032e: 2019 movs r0, #25 + 8000330: f7ff fedc bl 80000ec <NVIC_SetPriority> + + TIM16->CR2 = 0; + 8000334: 4b1f ldr r3, [pc, #124] ; (80003b4 <main+0x19a>) + 8000336: 2200 movs r2, #0 + 8000338: 605a str r2, [r3, #4] + TIM16->DIER = TIM_DIER_UIE; + 800033a: 4b1e ldr r3, [pc, #120] ; (80003b4 <main+0x19a>) + 800033c: 2201 movs r2, #1 + 800033e: 60da str r2, [r3, #12] + TIM16->PSC = 48-1; /* 1us */ + 8000340: 4b1c ldr r3, [pc, #112] ; (80003b4 <main+0x19a>) + 8000342: 222f movs r2, #47 ; 0x2f + 8000344: 629a str r2, [r3, #40] ; 0x28 + TIM16->ARR = 1000-1; /* 1ms */ + 8000346: 4b1b ldr r3, [pc, #108] ; (80003b4 <main+0x19a>) + 8000348: 4a1b ldr r2, [pc, #108] ; (80003b8 <main+0x19e>) + 800034a: 62da str r2, [r3, #44] ; 0x2c + TIM16->CR1 = TIM_CR1_CEN; + 800034c: 4b19 ldr r3, [pc, #100] ; (80003b4 <main+0x19a>) + 800034e: 2201 movs r2, #1 + 8000350: 601a str r2, [r3, #0] + + NVIC_EnableIRQ(TIM16_IRQn); + 8000352: 2015 movs r0, #21 + 8000354: f7ff feb4 bl 80000c0 <NVIC_EnableIRQ> + NVIC_SetPriority(TIM16_IRQn, 2<<5); + 8000358: 2140 movs r1, #64 ; 0x40 + 800035a: 2015 movs r0, #21 + 800035c: f7ff fec6 bl 80000ec <NVIC_SetPriority> + + adc_configure_scope_mode(1000000); + 8000360: 4b16 ldr r3, [pc, #88] ; (80003bc <main+0x1a2>) + 8000362: 0018 movs r0, r3 + 8000364: f000 f95a bl 800061c <adc_configure_scope_mode> + + usart_dma_init(); + 8000368: f000 fabe bl 80008e8 <usart_dma_init> + + while (42) { + char *data = "FOOBAR\n"; + 800036c: 4b14 ldr r3, [pc, #80] ; (80003c0 <main+0x1a6>) + 800036e: 603b str r3, [r7, #0] + usart_send_packet((uint8_t*)data, 8); + 8000370: 683b ldr r3, [r7, #0] + 8000372: 2108 movs r1, #8 + 8000374: 0018 movs r0, r3 + 8000376: f000 fb91 bl 8000a9c <usart_send_packet> + for (int i=0; i<100000; i++); + 800037a: 2300 movs r3, #0 + 800037c: 607b str r3, [r7, #4] + 800037e: e002 b.n 8000386 <main+0x16c> + 8000380: 687b ldr r3, [r7, #4] + 8000382: 3301 adds r3, #1 + 8000384: 607b str r3, [r7, #4] + 8000386: 687b ldr r3, [r7, #4] + 8000388: 4a0e ldr r2, [pc, #56] ; (80003c4 <main+0x1aa>) + 800038a: 4293 cmp r3, r2 + 800038c: ddf8 ble.n 8000380 <main+0x166> + while (42) { + 800038e: e7ed b.n 800036c <main+0x152> + 8000390: 40021000 .word 0x40021000 + 8000394: ffc3f80c .word 0xffc3f80c + 8000398: 20000000 .word 0x20000000 + 800039c: 00060011 .word 0x00060011 + 80003a0: 00425a01 .word 0x00425a01 + 80003a4: 0028a970 .word 0x0028a970 + 80003a8: 00088a80 .word 0x00088a80 + 80003ac: 48000400 .word 0x48000400 + 80003b0: 40013000 .word 0x40013000 + 80003b4: 40014400 .word 0x40014400 + 80003b8: 000003e7 .word 0x000003e7 + 80003bc: 000f4240 .word 0x000f4240 + 80003c0: 080018e4 .word 0x080018e4 + 80003c4: 0001869f .word 0x0001869f + +080003c8 <SPI1_IRQHandler>: + //for (int i=0; i<10000; i++) ; + //leds.error = 100; + } +} + +void SPI1_IRQHandler(void) { + 80003c8: b580 push {r7, lr} + 80003ca: af00 add r7, sp, #0 + if (SPI1->SR & SPI_SR_TXE) { + 80003cc: 4b08 ldr r3, [pc, #32] ; (80003f0 <SPI1_IRQHandler+0x28>) + 80003ce: 689b ldr r3, [r3, #8] + 80003d0: 2202 movs r2, #2 + 80003d2: 4013 ands r3, r2 + 80003d4: d009 beq.n 80003ea <SPI1_IRQHandler+0x22> + /* LED_STB */ + GPIOA->BSRR = 1<<3; + 80003d6: 2390 movs r3, #144 ; 0x90 + 80003d8: 05db lsls r3, r3, #23 + 80003da: 2208 movs r2, #8 + 80003dc: 619a str r2, [r3, #24] + SPI1->CR2 &= ~SPI_CR2_TXEIE; + 80003de: 4b04 ldr r3, [pc, #16] ; (80003f0 <SPI1_IRQHandler+0x28>) + 80003e0: 685a ldr r2, [r3, #4] + 80003e2: 4b03 ldr r3, [pc, #12] ; (80003f0 <SPI1_IRQHandler+0x28>) + 80003e4: 2180 movs r1, #128 ; 0x80 + 80003e6: 438a bics r2, r1 + 80003e8: 605a str r2, [r3, #4] + } +} + 80003ea: 46c0 nop ; (mov r8, r8) + 80003ec: 46bd mov sp, r7 + 80003ee: bd80 pop {r7, pc} + 80003f0: 40013000 .word 0x40013000 + +080003f4 <TIM16_IRQHandler>: + +void TIM16_IRQHandler(void) { + 80003f4: b580 push {r7, lr} + 80003f6: b082 sub sp, #8 + 80003f8: af00 add r7, sp, #0 + static int leds_update_counter = 0; + if (TIM16->SR & TIM_SR_UIF) { + 80003fa: 4b28 ldr r3, [pc, #160] ; (800049c <TIM16_IRQHandler+0xa8>) + 80003fc: 691b ldr r3, [r3, #16] + 80003fe: 2201 movs r2, #1 + 8000400: 4013 ands r3, r2 + 8000402: d047 beq.n 8000494 <TIM16_IRQHandler+0xa0> + TIM16->SR &= ~TIM_SR_UIF; + 8000404: 4b25 ldr r3, [pc, #148] ; (800049c <TIM16_IRQHandler+0xa8>) + 8000406: 691a ldr r2, [r3, #16] + 8000408: 4b24 ldr r3, [pc, #144] ; (800049c <TIM16_IRQHandler+0xa8>) + 800040a: 2101 movs r1, #1 + 800040c: 438a bics r2, r1 + 800040e: 611a str r2, [r3, #16] + + uint8_t bits = 0, mask = 1; + 8000410: 1dfb adds r3, r7, #7 + 8000412: 2200 movs r2, #0 + 8000414: 701a strb r2, [r3, #0] + 8000416: 1dbb adds r3, r7, #6 + 8000418: 2201 movs r2, #1 + 800041a: 701a strb r2, [r3, #0] + for (size_t i=0; i<sizeof(leds)/sizeof(leds.arr[0]); i++) { + 800041c: 2300 movs r3, #0 + 800041e: 603b str r3, [r7, #0] + 8000420: e01d b.n 800045e <TIM16_IRQHandler+0x6a> + if (leds.arr[i]) { + 8000422: 4b1f ldr r3, [pc, #124] ; (80004a0 <TIM16_IRQHandler+0xac>) + 8000424: 683a ldr r2, [r7, #0] + 8000426: 0092 lsls r2, r2, #2 + 8000428: 58d3 ldr r3, [r2, r3] + 800042a: 2b00 cmp r3, #0 + 800042c: d00f beq.n 800044e <TIM16_IRQHandler+0x5a> + leds.arr[i]--; + 800042e: 4b1c ldr r3, [pc, #112] ; (80004a0 <TIM16_IRQHandler+0xac>) + 8000430: 683a ldr r2, [r7, #0] + 8000432: 0092 lsls r2, r2, #2 + 8000434: 58d3 ldr r3, [r2, r3] + 8000436: 1e59 subs r1, r3, #1 + 8000438: 4b19 ldr r3, [pc, #100] ; (80004a0 <TIM16_IRQHandler+0xac>) + 800043a: 683a ldr r2, [r7, #0] + 800043c: 0092 lsls r2, r2, #2 + 800043e: 50d1 str r1, [r2, r3] + bits |= mask; + 8000440: 1dfb adds r3, r7, #7 + 8000442: 1df9 adds r1, r7, #7 + 8000444: 1dba adds r2, r7, #6 + 8000446: 7809 ldrb r1, [r1, #0] + 8000448: 7812 ldrb r2, [r2, #0] + 800044a: 430a orrs r2, r1 + 800044c: 701a strb r2, [r3, #0] + } + mask <<= 1; + 800044e: 1dba adds r2, r7, #6 + 8000450: 1dbb adds r3, r7, #6 + 8000452: 781b ldrb r3, [r3, #0] + 8000454: 18db adds r3, r3, r3 + 8000456: 7013 strb r3, [r2, #0] + for (size_t i=0; i<sizeof(leds)/sizeof(leds.arr[0]); i++) { + 8000458: 683b ldr r3, [r7, #0] + 800045a: 3301 adds r3, #1 + 800045c: 603b str r3, [r7, #0] + 800045e: 683b ldr r3, [r7, #0] + 8000460: 2b07 cmp r3, #7 + 8000462: d9de bls.n 8000422 <TIM16_IRQHandler+0x2e> + } + + if (leds_update_counter++ == 10) { + 8000464: 4b0f ldr r3, [pc, #60] ; (80004a4 <TIM16_IRQHandler+0xb0>) + 8000466: 681b ldr r3, [r3, #0] + 8000468: 1c59 adds r1, r3, #1 + 800046a: 4a0e ldr r2, [pc, #56] ; (80004a4 <TIM16_IRQHandler+0xb0>) + 800046c: 6011 str r1, [r2, #0] + 800046e: 2b0a cmp r3, #10 + 8000470: d110 bne.n 8000494 <TIM16_IRQHandler+0xa0> + leds_update_counter = 0; + 8000472: 4b0c ldr r3, [pc, #48] ; (80004a4 <TIM16_IRQHandler+0xb0>) + 8000474: 2200 movs r2, #0 + 8000476: 601a str r2, [r3, #0] + + /* Workaround for SPI hardware bug: Even if configured to 8-bit mode, the SPI will do a 16-bit transfer if the + * data register is accessed through a 16-bit write. Unfortunately, the STMCube register defs define DR as an + * uint16_t, so we have to do some magic here to force an 8-bit write. */ + *((volatile uint8_t*)&(SPI1->DR)) = bits; + 8000478: 4a0b ldr r2, [pc, #44] ; (80004a8 <TIM16_IRQHandler+0xb4>) + 800047a: 1dfb adds r3, r7, #7 + 800047c: 781b ldrb r3, [r3, #0] + 800047e: 7013 strb r3, [r2, #0] + SPI1->CR2 |= SPI_CR2_TXEIE; + 8000480: 4b0a ldr r3, [pc, #40] ; (80004ac <TIM16_IRQHandler+0xb8>) + 8000482: 685a ldr r2, [r3, #4] + 8000484: 4b09 ldr r3, [pc, #36] ; (80004ac <TIM16_IRQHandler+0xb8>) + 8000486: 2180 movs r1, #128 ; 0x80 + 8000488: 430a orrs r2, r1 + 800048a: 605a str r2, [r3, #4] + GPIOA->BRR = 1<<3; + 800048c: 2390 movs r3, #144 ; 0x90 + 800048e: 05db lsls r3, r3, #23 + 8000490: 2208 movs r2, #8 + 8000492: 629a str r2, [r3, #40] ; 0x28 + } + } +} + 8000494: 46c0 nop ; (mov r8, r8) + 8000496: 46bd mov sp, r7 + 8000498: b002 add sp, #8 + 800049a: bd80 pop {r7, pc} + 800049c: 40014400 .word 0x40014400 + 80004a0: 200000a8 .word 0x200000a8 + 80004a4: 20000098 .word 0x20000098 + 80004a8: 4001300c .word 0x4001300c + 80004ac: 40013000 .word 0x40013000 + +080004b0 <NMI_Handler>: + +void NMI_Handler(void) { + 80004b0: b580 push {r7, lr} + 80004b2: af00 add r7, sp, #0 + asm volatile ("bkpt"); + 80004b4: be00 bkpt 0x0000 +} + 80004b6: 46c0 nop ; (mov r8, r8) + 80004b8: 46bd mov sp, r7 + 80004ba: bd80 pop {r7, pc} + +080004bc <HardFault_Handler>: + +void HardFault_Handler(void) __attribute__((naked)); +void HardFault_Handler() { + asm volatile ("bkpt"); + 80004bc: be00 bkpt 0x0000 +} + 80004be: 46c0 nop ; (mov r8, r8) + +080004c0 <SVC_Handler>: + +void SVC_Handler(void) { + 80004c0: b580 push {r7, lr} + 80004c2: af00 add r7, sp, #0 + asm volatile ("bkpt"); + 80004c4: be00 bkpt 0x0000 +} + 80004c6: 46c0 nop ; (mov r8, r8) + 80004c8: 46bd mov sp, r7 + 80004ca: bd80 pop {r7, pc} + +080004cc <PendSV_Handler>: + + +void PendSV_Handler(void) { + 80004cc: b580 push {r7, lr} + 80004ce: af00 add r7, sp, #0 + asm volatile ("bkpt"); + 80004d0: be00 bkpt 0x0000 +} + 80004d2: 46c0 nop ; (mov r8, r8) + 80004d4: 46bd mov sp, r7 + 80004d6: bd80 pop {r7, pc} + +080004d8 <SysTick_Handler>: + +void SysTick_Handler(void) { + 80004d8: b580 push {r7, lr} + 80004da: af00 add r7, sp, #0 + static int n = 0; + if (n++ == 10) { + 80004dc: 4b0a ldr r3, [pc, #40] ; (8000508 <SysTick_Handler+0x30>) + 80004de: 681b ldr r3, [r3, #0] + 80004e0: 1c59 adds r1, r3, #1 + 80004e2: 4a09 ldr r2, [pc, #36] ; (8000508 <SysTick_Handler+0x30>) + 80004e4: 6011 str r1, [r2, #0] + 80004e6: 2b0a cmp r3, #10 + 80004e8: d10a bne.n 8000500 <SysTick_Handler+0x28> + n = 0; + 80004ea: 4b07 ldr r3, [pc, #28] ; (8000508 <SysTick_Handler+0x30>) + 80004ec: 2200 movs r2, #0 + 80004ee: 601a str r2, [r3, #0] + sys_time_seconds++; + 80004f0: 4b06 ldr r3, [pc, #24] ; (800050c <SysTick_Handler+0x34>) + 80004f2: 681b ldr r3, [r3, #0] + 80004f4: 1c5a adds r2, r3, #1 + 80004f6: 4b05 ldr r3, [pc, #20] ; (800050c <SysTick_Handler+0x34>) + 80004f8: 601a str r2, [r3, #0] + leds.pps = 100; /* ms */ + 80004fa: 4b05 ldr r3, [pc, #20] ; (8000510 <SysTick_Handler+0x38>) + 80004fc: 2264 movs r2, #100 ; 0x64 + 80004fe: 619a str r2, [r3, #24] + } +} + 8000500: 46c0 nop ; (mov r8, r8) + 8000502: 46bd mov sp, r7 + 8000504: bd80 pop {r7, pc} + 8000506: 46c0 nop ; (mov r8, r8) + 8000508: 2000009c .word 0x2000009c + 800050c: 20000094 .word 0x20000094 + 8000510: 200000a8 .word 0x200000a8 + +08000514 <NVIC_EnableIRQ>: +{ + 8000514: b580 push {r7, lr} + 8000516: b082 sub sp, #8 + 8000518: af00 add r7, sp, #0 + 800051a: 0002 movs r2, r0 + 800051c: 1dfb adds r3, r7, #7 + 800051e: 701a strb r2, [r3, #0] + NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + 8000520: 1dfb adds r3, r7, #7 + 8000522: 781b ldrb r3, [r3, #0] + 8000524: 001a movs r2, r3 + 8000526: 231f movs r3, #31 + 8000528: 401a ands r2, r3 + 800052a: 4b04 ldr r3, [pc, #16] ; (800053c <NVIC_EnableIRQ+0x28>) + 800052c: 2101 movs r1, #1 + 800052e: 4091 lsls r1, r2 + 8000530: 000a movs r2, r1 + 8000532: 601a str r2, [r3, #0] +} + 8000534: 46c0 nop ; (mov r8, r8) + 8000536: 46bd mov sp, r7 + 8000538: b002 add sp, #8 + 800053a: bd80 pop {r7, pc} + 800053c: e000e100 .word 0xe000e100 + +08000540 <NVIC_SetPriority>: +{ + 8000540: b590 push {r4, r7, lr} + 8000542: b083 sub sp, #12 + 8000544: af00 add r7, sp, #0 + 8000546: 0002 movs r2, r0 + 8000548: 6039 str r1, [r7, #0] + 800054a: 1dfb adds r3, r7, #7 + 800054c: 701a strb r2, [r3, #0] + if ((int32_t)(IRQn) < 0) + 800054e: 1dfb adds r3, r7, #7 + 8000550: 781b ldrb r3, [r3, #0] + 8000552: 2b7f cmp r3, #127 ; 0x7f + 8000554: d932 bls.n 80005bc <NVIC_SetPriority+0x7c> + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + 8000556: 4a2f ldr r2, [pc, #188] ; (8000614 <NVIC_SetPriority+0xd4>) + 8000558: 1dfb adds r3, r7, #7 + 800055a: 781b ldrb r3, [r3, #0] + 800055c: 0019 movs r1, r3 + 800055e: 230f movs r3, #15 + 8000560: 400b ands r3, r1 + 8000562: 3b08 subs r3, #8 + 8000564: 089b lsrs r3, r3, #2 + 8000566: 3306 adds r3, #6 + 8000568: 009b lsls r3, r3, #2 + 800056a: 18d3 adds r3, r2, r3 + 800056c: 3304 adds r3, #4 + 800056e: 681b ldr r3, [r3, #0] + 8000570: 1dfa adds r2, r7, #7 + 8000572: 7812 ldrb r2, [r2, #0] + 8000574: 0011 movs r1, r2 + 8000576: 2203 movs r2, #3 + 8000578: 400a ands r2, r1 + 800057a: 00d2 lsls r2, r2, #3 + 800057c: 21ff movs r1, #255 ; 0xff + 800057e: 4091 lsls r1, r2 + 8000580: 000a movs r2, r1 + 8000582: 43d2 mvns r2, r2 + 8000584: 401a ands r2, r3 + 8000586: 0011 movs r1, r2 + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + 8000588: 683b ldr r3, [r7, #0] + 800058a: 019b lsls r3, r3, #6 + 800058c: 22ff movs r2, #255 ; 0xff + 800058e: 401a ands r2, r3 + 8000590: 1dfb adds r3, r7, #7 + 8000592: 781b ldrb r3, [r3, #0] + 8000594: 0018 movs r0, r3 + 8000596: 2303 movs r3, #3 + 8000598: 4003 ands r3, r0 + 800059a: 00db lsls r3, r3, #3 + 800059c: 409a lsls r2, r3 + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + 800059e: 481d ldr r0, [pc, #116] ; (8000614 <NVIC_SetPriority+0xd4>) + 80005a0: 1dfb adds r3, r7, #7 + 80005a2: 781b ldrb r3, [r3, #0] + 80005a4: 001c movs r4, r3 + 80005a6: 230f movs r3, #15 + 80005a8: 4023 ands r3, r4 + 80005aa: 3b08 subs r3, #8 + 80005ac: 089b lsrs r3, r3, #2 + 80005ae: 430a orrs r2, r1 + 80005b0: 3306 adds r3, #6 + 80005b2: 009b lsls r3, r3, #2 + 80005b4: 18c3 adds r3, r0, r3 + 80005b6: 3304 adds r3, #4 + 80005b8: 601a str r2, [r3, #0] +} + 80005ba: e027 b.n 800060c <NVIC_SetPriority+0xcc> + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + 80005bc: 4a16 ldr r2, [pc, #88] ; (8000618 <NVIC_SetPriority+0xd8>) + 80005be: 1dfb adds r3, r7, #7 + 80005c0: 781b ldrb r3, [r3, #0] + 80005c2: b25b sxtb r3, r3 + 80005c4: 089b lsrs r3, r3, #2 + 80005c6: 33c0 adds r3, #192 ; 0xc0 + 80005c8: 009b lsls r3, r3, #2 + 80005ca: 589b ldr r3, [r3, r2] + 80005cc: 1dfa adds r2, r7, #7 + 80005ce: 7812 ldrb r2, [r2, #0] + 80005d0: 0011 movs r1, r2 + 80005d2: 2203 movs r2, #3 + 80005d4: 400a ands r2, r1 + 80005d6: 00d2 lsls r2, r2, #3 + 80005d8: 21ff movs r1, #255 ; 0xff + 80005da: 4091 lsls r1, r2 + 80005dc: 000a movs r2, r1 + 80005de: 43d2 mvns r2, r2 + 80005e0: 401a ands r2, r3 + 80005e2: 0011 movs r1, r2 + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + 80005e4: 683b ldr r3, [r7, #0] + 80005e6: 019b lsls r3, r3, #6 + 80005e8: 22ff movs r2, #255 ; 0xff + 80005ea: 401a ands r2, r3 + 80005ec: 1dfb adds r3, r7, #7 + 80005ee: 781b ldrb r3, [r3, #0] + 80005f0: 0018 movs r0, r3 + 80005f2: 2303 movs r3, #3 + 80005f4: 4003 ands r3, r0 + 80005f6: 00db lsls r3, r3, #3 + 80005f8: 409a lsls r2, r3 + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + 80005fa: 4807 ldr r0, [pc, #28] ; (8000618 <NVIC_SetPriority+0xd8>) + 80005fc: 1dfb adds r3, r7, #7 + 80005fe: 781b ldrb r3, [r3, #0] + 8000600: b25b sxtb r3, r3 + 8000602: 089b lsrs r3, r3, #2 + 8000604: 430a orrs r2, r1 + 8000606: 33c0 adds r3, #192 ; 0xc0 + 8000608: 009b lsls r3, r3, #2 + 800060a: 501a str r2, [r3, r0] +} + 800060c: 46c0 nop ; (mov r8, r8) + 800060e: 46bd mov sp, r7 + 8000610: b003 add sp, #12 + 8000612: bd90 pop {r4, r7, pc} + 8000614: e000ed00 .word 0xe000ed00 + 8000618: e000e100 .word 0xe000e100 + +0800061c <adc_configure_scope_mode>: +static void adc_dma_init(int burstlen); +static void adc_timer_init(int psc, int ivl); + + +/* Mode that can be used for debugging */ +void adc_configure_scope_mode(int sampling_interval_ns) { + 800061c: b580 push {r7, lr} + 800061e: b084 sub sp, #16 + 8000620: af00 add r7, sp, #0 + 8000622: 6078 str r0, [r7, #4] + adc_dma_init(sizeof(adc_buf)/sizeof(adc_buf[0])); + 8000624: 2380 movs r3, #128 ; 0x80 + 8000626: 00db lsls r3, r3, #3 + 8000628: 0018 movs r0, r3 + 800062a: f000 f84b bl 80006c4 <adc_dma_init> + + /* Clock from PCLK/4 instead of the internal exclusive high-speed RC oscillator. */ + ADC1->CFGR2 = (2<<ADC_CFGR2_CKMODE_Pos); /* Use PCLK/4=12MHz */ + 800062e: 4b21 ldr r3, [pc, #132] ; (80006b4 <adc_configure_scope_mode+0x98>) + 8000630: 2280 movs r2, #128 ; 0x80 + 8000632: 0612 lsls r2, r2, #24 + 8000634: 611a str r2, [r3, #16] + /* Sampling time 239.5 ADC clock cycles -> total conversion time 38.5us*/ + ADC1->SMPR = (7<<ADC_SMPR_SMP_Pos); + 8000636: 4b1f ldr r3, [pc, #124] ; (80006b4 <adc_configure_scope_mode+0x98>) + 8000638: 2207 movs r2, #7 + 800063a: 615a str r2, [r3, #20] + + /* Setup DMA and triggering */ + /* Trigger from TIM1 TRGO */ + ADC1->CFGR1 = ADC_CFGR1_DMAEN | ADC_CFGR1_DMACFG | (2<<ADC_CFGR1_EXTEN_Pos) | (1<<ADC_CFGR1_EXTSEL_Pos); + 800063c: 4b1d ldr r3, [pc, #116] ; (80006b4 <adc_configure_scope_mode+0x98>) + 800063e: 4a1e ldr r2, [pc, #120] ; (80006b8 <adc_configure_scope_mode+0x9c>) + 8000640: 60da str r2, [r3, #12] + ADC1->CHSELR = ADC_CHSELR_CHSEL2; + 8000642: 4b1c ldr r3, [pc, #112] ; (80006b4 <adc_configure_scope_mode+0x98>) + 8000644: 2204 movs r2, #4 + 8000646: 629a str r2, [r3, #40] ; 0x28 + /* Perform self-calibration */ + ADC1->CR |= ADC_CR_ADCAL; + 8000648: 4b1a ldr r3, [pc, #104] ; (80006b4 <adc_configure_scope_mode+0x98>) + 800064a: 689a ldr r2, [r3, #8] + 800064c: 4b19 ldr r3, [pc, #100] ; (80006b4 <adc_configure_scope_mode+0x98>) + 800064e: 2180 movs r1, #128 ; 0x80 + 8000650: 0609 lsls r1, r1, #24 + 8000652: 430a orrs r2, r1 + 8000654: 609a str r2, [r3, #8] + while (ADC1->CR & ADC_CR_ADCAL) + 8000656: 46c0 nop ; (mov r8, r8) + 8000658: 4b16 ldr r3, [pc, #88] ; (80006b4 <adc_configure_scope_mode+0x98>) + 800065a: 689b ldr r3, [r3, #8] + 800065c: 2b00 cmp r3, #0 + 800065e: dbfb blt.n 8000658 <adc_configure_scope_mode+0x3c> + ; + /* Enable conversion */ + ADC1->CR |= ADC_CR_ADEN; + 8000660: 4b14 ldr r3, [pc, #80] ; (80006b4 <adc_configure_scope_mode+0x98>) + 8000662: 689a ldr r2, [r3, #8] + 8000664: 4b13 ldr r3, [pc, #76] ; (80006b4 <adc_configure_scope_mode+0x98>) + 8000666: 2101 movs r1, #1 + 8000668: 430a orrs r2, r1 + 800066a: 609a str r2, [r3, #8] + ADC1->CR |= ADC_CR_ADSTART; + 800066c: 4b11 ldr r3, [pc, #68] ; (80006b4 <adc_configure_scope_mode+0x98>) + 800066e: 689a ldr r2, [r3, #8] + 8000670: 4b10 ldr r3, [pc, #64] ; (80006b4 <adc_configure_scope_mode+0x98>) + 8000672: 2104 movs r1, #4 + 8000674: 430a orrs r2, r1 + 8000676: 609a str r2, [r3, #8] + + /* An ADC conversion takes 1.1667us, so to be sure we don't get data overruns we limit sampling to every 1.5us. + Since we don't have a spare PLL to generate the ADC sample clock and re-configuring the system clock just for this + would be overkill we round to 250ns increments. The minimum sampling rate is about 60Hz due to timer resolution. */ + int cycles = sampling_interval_ns > 1500 ? sampling_interval_ns/250 : 6; + 8000678: 687b ldr r3, [r7, #4] + 800067a: 4a10 ldr r2, [pc, #64] ; (80006bc <adc_configure_scope_mode+0xa0>) + 800067c: 4293 cmp r3, r2 + 800067e: dd06 ble.n 800068e <adc_configure_scope_mode+0x72> + 8000680: 687b ldr r3, [r7, #4] + 8000682: 21fa movs r1, #250 ; 0xfa + 8000684: 0018 movs r0, r3 + 8000686: f001 f819 bl 80016bc <__divsi3> + 800068a: 0003 movs r3, r0 + 800068c: e000 b.n 8000690 <adc_configure_scope_mode+0x74> + 800068e: 2306 movs r3, #6 + 8000690: 60fb str r3, [r7, #12] + if (cycles > 0xffff) + 8000692: 68fa ldr r2, [r7, #12] + 8000694: 2380 movs r3, #128 ; 0x80 + 8000696: 025b lsls r3, r3, #9 + 8000698: 429a cmp r2, r3 + 800069a: db01 blt.n 80006a0 <adc_configure_scope_mode+0x84> + cycles = 0xffff; + 800069c: 4b08 ldr r3, [pc, #32] ; (80006c0 <adc_configure_scope_mode+0xa4>) + 800069e: 60fb str r3, [r7, #12] + adc_timer_init(12/*250ns/tick*/, cycles); + 80006a0: 68fb ldr r3, [r7, #12] + 80006a2: 0019 movs r1, r3 + 80006a4: 200c movs r0, #12 + 80006a6: f000 f83d bl 8000724 <adc_timer_init> +} + 80006aa: 46c0 nop ; (mov r8, r8) + 80006ac: 46bd mov sp, r7 + 80006ae: b004 add sp, #16 + 80006b0: bd80 pop {r7, pc} + 80006b2: 46c0 nop ; (mov r8, r8) + 80006b4: 40012400 .word 0x40012400 + 80006b8: 00000843 .word 0x00000843 + 80006bc: 000005dc .word 0x000005dc + 80006c0: 0000ffff .word 0x0000ffff + +080006c4 <adc_dma_init>: + +/* FIXME figure out the proper place to configure this. */ +#define ADC_TIMER_INTERVAL_US 20 + +static void adc_dma_init(int burstlen) { + 80006c4: b580 push {r7, lr} + 80006c6: b082 sub sp, #8 + 80006c8: af00 add r7, sp, #0 + 80006ca: 6078 str r0, [r7, #4] + /* Configure DMA 1 Channel 1 to get rid of all the data */ + DMA1_Channel1->CPAR = (unsigned int)&ADC1->DR; + 80006cc: 4b11 ldr r3, [pc, #68] ; (8000714 <adc_dma_init+0x50>) + 80006ce: 4a12 ldr r2, [pc, #72] ; (8000718 <adc_dma_init+0x54>) + 80006d0: 609a str r2, [r3, #8] + DMA1_Channel1->CMAR = (unsigned int)&adc_buf; + 80006d2: 4b10 ldr r3, [pc, #64] ; (8000714 <adc_dma_init+0x50>) + 80006d4: 4a11 ldr r2, [pc, #68] ; (800071c <adc_dma_init+0x58>) + 80006d6: 60da str r2, [r3, #12] + DMA1_Channel1->CNDTR = burstlen; + 80006d8: 4b0e ldr r3, [pc, #56] ; (8000714 <adc_dma_init+0x50>) + 80006da: 687a ldr r2, [r7, #4] + 80006dc: 605a str r2, [r3, #4] + DMA1_Channel1->CCR = (0<<DMA_CCR_PL_Pos); + 80006de: 4b0d ldr r3, [pc, #52] ; (8000714 <adc_dma_init+0x50>) + 80006e0: 2200 movs r2, #0 + 80006e2: 601a str r2, [r3, #0] + DMA1_Channel1->CCR |= + 80006e4: 4b0b ldr r3, [pc, #44] ; (8000714 <adc_dma_init+0x50>) + 80006e6: 681a ldr r2, [r3, #0] + 80006e8: 4b0a ldr r3, [pc, #40] ; (8000714 <adc_dma_init+0x50>) + 80006ea: 490d ldr r1, [pc, #52] ; (8000720 <adc_dma_init+0x5c>) + 80006ec: 430a orrs r2, r1 + 80006ee: 601a str r2, [r3, #0] + | (1<<DMA_CCR_PSIZE_Pos) /* 16 bit */ + | DMA_CCR_MINC + | DMA_CCR_TCIE; /* Enable transfer complete interrupt. */ + + /* triggered on transfer completion. We use this to process the ADC data */ + NVIC_EnableIRQ(DMA1_Channel1_IRQn); + 80006f0: 2009 movs r0, #9 + 80006f2: f7ff ff0f bl 8000514 <NVIC_EnableIRQ> + NVIC_SetPriority(DMA1_Channel1_IRQn, 2<<5); + 80006f6: 2140 movs r1, #64 ; 0x40 + 80006f8: 2009 movs r0, #9 + 80006fa: f7ff ff21 bl 8000540 <NVIC_SetPriority> + + DMA1_Channel1->CCR |= DMA_CCR_EN; /* Enable channel */ + 80006fe: 4b05 ldr r3, [pc, #20] ; (8000714 <adc_dma_init+0x50>) + 8000700: 681a ldr r2, [r3, #0] + 8000702: 4b04 ldr r3, [pc, #16] ; (8000714 <adc_dma_init+0x50>) + 8000704: 2101 movs r1, #1 + 8000706: 430a orrs r2, r1 + 8000708: 601a str r2, [r3, #0] +} + 800070a: 46c0 nop ; (mov r8, r8) + 800070c: 46bd mov sp, r7 + 800070e: b002 add sp, #8 + 8000710: bd80 pop {r7, pc} + 8000712: 46c0 nop ; (mov r8, r8) + 8000714: 40020008 .word 0x40020008 + 8000718: 40012440 .word 0x40012440 + 800071c: 200000c8 .word 0x200000c8 + 8000720: 000005a2 .word 0x000005a2 + +08000724 <adc_timer_init>: + +static void adc_timer_init(int psc, int ivl) { + 8000724: b580 push {r7, lr} + 8000726: b082 sub sp, #8 + 8000728: af00 add r7, sp, #0 + 800072a: 6078 str r0, [r7, #4] + 800072c: 6039 str r1, [r7, #0] + TIM1->BDTR = TIM_BDTR_MOE; /* MOE is needed even though we only "output" a chip-internal signal TODO: Verify this. */ + 800072e: 4b15 ldr r3, [pc, #84] ; (8000784 <adc_timer_init+0x60>) + 8000730: 2280 movs r2, #128 ; 0x80 + 8000732: 0212 lsls r2, r2, #8 + 8000734: 645a str r2, [r3, #68] ; 0x44 + TIM1->CCMR2 = (6<<TIM_CCMR2_OC4M_Pos); /* PWM Mode 1 to get a clean trigger signal */ + 8000736: 4b13 ldr r3, [pc, #76] ; (8000784 <adc_timer_init+0x60>) + 8000738: 22c0 movs r2, #192 ; 0xc0 + 800073a: 01d2 lsls r2, r2, #7 + 800073c: 61da str r2, [r3, #28] + TIM1->CCER = TIM_CCER_CC4E; /* Enable capture/compare unit 4 connected to ADC */ + 800073e: 4b11 ldr r3, [pc, #68] ; (8000784 <adc_timer_init+0x60>) + 8000740: 2280 movs r2, #128 ; 0x80 + 8000742: 0152 lsls r2, r2, #5 + 8000744: 621a str r2, [r3, #32] + TIM1->CCR4 = 1; /* Trigger at start of timer cycle */ + 8000746: 4b0f ldr r3, [pc, #60] ; (8000784 <adc_timer_init+0x60>) + 8000748: 2201 movs r2, #1 + 800074a: 641a str r2, [r3, #64] ; 0x40 + /* Set prescaler and interval */ + TIM1->PSC = psc-1; + 800074c: 687b ldr r3, [r7, #4] + 800074e: 1e5a subs r2, r3, #1 + 8000750: 4b0c ldr r3, [pc, #48] ; (8000784 <adc_timer_init+0x60>) + 8000752: 629a str r2, [r3, #40] ; 0x28 + TIM1->ARR = ivl-1; + 8000754: 683b ldr r3, [r7, #0] + 8000756: 1e5a subs r2, r3, #1 + 8000758: 4b0a ldr r3, [pc, #40] ; (8000784 <adc_timer_init+0x60>) + 800075a: 62da str r2, [r3, #44] ; 0x2c + /* Preload all values */ + TIM1->EGR |= TIM_EGR_UG; + 800075c: 4b09 ldr r3, [pc, #36] ; (8000784 <adc_timer_init+0x60>) + 800075e: 695a ldr r2, [r3, #20] + 8000760: 4b08 ldr r3, [pc, #32] ; (8000784 <adc_timer_init+0x60>) + 8000762: 2101 movs r1, #1 + 8000764: 430a orrs r2, r1 + 8000766: 615a str r2, [r3, #20] + TIM1->CR1 = TIM_CR1_ARPE; + 8000768: 4b06 ldr r3, [pc, #24] ; (8000784 <adc_timer_init+0x60>) + 800076a: 2280 movs r2, #128 ; 0x80 + 800076c: 601a str r2, [r3, #0] + /* And... go! */ + TIM1->CR1 |= TIM_CR1_CEN; + 800076e: 4b05 ldr r3, [pc, #20] ; (8000784 <adc_timer_init+0x60>) + 8000770: 681a ldr r2, [r3, #0] + 8000772: 4b04 ldr r3, [pc, #16] ; (8000784 <adc_timer_init+0x60>) + 8000774: 2101 movs r1, #1 + 8000776: 430a orrs r2, r1 + 8000778: 601a str r2, [r3, #0] +} + 800077a: 46c0 nop ; (mov r8, r8) + 800077c: 46bd mov sp, r7 + 800077e: b002 add sp, #8 + 8000780: bd80 pop {r7, pc} + 8000782: 46c0 nop ; (mov r8, r8) + 8000784: 40012c00 .word 0x40012c00 + +08000788 <gdb_dump>: + +/* This acts as a no-op that provides a convenient point to set a breakpoint for the debug scope logic */ +static void gdb_dump(void) { + 8000788: b580 push {r7, lr} + 800078a: af00 add r7, sp, #0 +} + 800078c: 46c0 nop ; (mov r8, r8) + 800078e: 46bd mov sp, r7 + 8000790: bd80 pop {r7, pc} + +08000792 <DMA1_Channel1_IRQHandler>: + +void DMA1_Channel1_IRQHandler(void) { + 8000792: b580 push {r7, lr} + 8000794: af00 add r7, sp, #0 + /* Clear the interrupt flag */ + DMA1->IFCR |= DMA_IFCR_CGIF1; + 8000796: 4b05 ldr r3, [pc, #20] ; (80007ac <DMA1_Channel1_IRQHandler+0x1a>) + 8000798: 685a ldr r2, [r3, #4] + 800079a: 4b04 ldr r3, [pc, #16] ; (80007ac <DMA1_Channel1_IRQHandler+0x1a>) + 800079c: 2101 movs r1, #1 + 800079e: 430a orrs r2, r1 + 80007a0: 605a str r2, [r3, #4] + gdb_dump(); + 80007a2: f7ff fff1 bl 8000788 <gdb_dump> + adc_buf[i] = -255; + } + } + } + */ +} + 80007a6: 46c0 nop ; (mov r8, r8) + 80007a8: 46bd mov sp, r7 + 80007aa: bd80 pop {r7, pc} + 80007ac: 40020000 .word 0x40020000 + +080007b0 <NVIC_EnableIRQ>: +{ + 80007b0: b580 push {r7, lr} + 80007b2: b082 sub sp, #8 + 80007b4: af00 add r7, sp, #0 + 80007b6: 0002 movs r2, r0 + 80007b8: 1dfb adds r3, r7, #7 + 80007ba: 701a strb r2, [r3, #0] + NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + 80007bc: 1dfb adds r3, r7, #7 + 80007be: 781b ldrb r3, [r3, #0] + 80007c0: 001a movs r2, r3 + 80007c2: 231f movs r3, #31 + 80007c4: 401a ands r2, r3 + 80007c6: 4b04 ldr r3, [pc, #16] ; (80007d8 <NVIC_EnableIRQ+0x28>) + 80007c8: 2101 movs r1, #1 + 80007ca: 4091 lsls r1, r2 + 80007cc: 000a movs r2, r1 + 80007ce: 601a str r2, [r3, #0] +} + 80007d0: 46c0 nop ; (mov r8, r8) + 80007d2: 46bd mov sp, r7 + 80007d4: b002 add sp, #8 + 80007d6: bd80 pop {r7, pc} + 80007d8: e000e100 .word 0xe000e100 + +080007dc <NVIC_DisableIRQ>: +{ + 80007dc: b580 push {r7, lr} + 80007de: b082 sub sp, #8 + 80007e0: af00 add r7, sp, #0 + 80007e2: 0002 movs r2, r0 + 80007e4: 1dfb adds r3, r7, #7 + 80007e6: 701a strb r2, [r3, #0] + NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); + 80007e8: 1dfb adds r3, r7, #7 + 80007ea: 781b ldrb r3, [r3, #0] + 80007ec: 001a movs r2, r3 + 80007ee: 231f movs r3, #31 + 80007f0: 4013 ands r3, r2 + 80007f2: 4905 ldr r1, [pc, #20] ; (8000808 <NVIC_DisableIRQ+0x2c>) + 80007f4: 2201 movs r2, #1 + 80007f6: 409a lsls r2, r3 + 80007f8: 0013 movs r3, r2 + 80007fa: 2280 movs r2, #128 ; 0x80 + 80007fc: 508b str r3, [r1, r2] +} + 80007fe: 46c0 nop ; (mov r8, r8) + 8000800: 46bd mov sp, r7 + 8000802: b002 add sp, #8 + 8000804: bd80 pop {r7, pc} + 8000806: 46c0 nop ; (mov r8, r8) + 8000808: e000e100 .word 0xe000e100 + +0800080c <NVIC_SetPriority>: +{ + 800080c: b590 push {r4, r7, lr} + 800080e: b083 sub sp, #12 + 8000810: af00 add r7, sp, #0 + 8000812: 0002 movs r2, r0 + 8000814: 6039 str r1, [r7, #0] + 8000816: 1dfb adds r3, r7, #7 + 8000818: 701a strb r2, [r3, #0] + if ((int32_t)(IRQn) < 0) + 800081a: 1dfb adds r3, r7, #7 + 800081c: 781b ldrb r3, [r3, #0] + 800081e: 2b7f cmp r3, #127 ; 0x7f + 8000820: d932 bls.n 8000888 <NVIC_SetPriority+0x7c> + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + 8000822: 4a2f ldr r2, [pc, #188] ; (80008e0 <NVIC_SetPriority+0xd4>) + 8000824: 1dfb adds r3, r7, #7 + 8000826: 781b ldrb r3, [r3, #0] + 8000828: 0019 movs r1, r3 + 800082a: 230f movs r3, #15 + 800082c: 400b ands r3, r1 + 800082e: 3b08 subs r3, #8 + 8000830: 089b lsrs r3, r3, #2 + 8000832: 3306 adds r3, #6 + 8000834: 009b lsls r3, r3, #2 + 8000836: 18d3 adds r3, r2, r3 + 8000838: 3304 adds r3, #4 + 800083a: 681b ldr r3, [r3, #0] + 800083c: 1dfa adds r2, r7, #7 + 800083e: 7812 ldrb r2, [r2, #0] + 8000840: 0011 movs r1, r2 + 8000842: 2203 movs r2, #3 + 8000844: 400a ands r2, r1 + 8000846: 00d2 lsls r2, r2, #3 + 8000848: 21ff movs r1, #255 ; 0xff + 800084a: 4091 lsls r1, r2 + 800084c: 000a movs r2, r1 + 800084e: 43d2 mvns r2, r2 + 8000850: 401a ands r2, r3 + 8000852: 0011 movs r1, r2 + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + 8000854: 683b ldr r3, [r7, #0] + 8000856: 019b lsls r3, r3, #6 + 8000858: 22ff movs r2, #255 ; 0xff + 800085a: 401a ands r2, r3 + 800085c: 1dfb adds r3, r7, #7 + 800085e: 781b ldrb r3, [r3, #0] + 8000860: 0018 movs r0, r3 + 8000862: 2303 movs r3, #3 + 8000864: 4003 ands r3, r0 + 8000866: 00db lsls r3, r3, #3 + 8000868: 409a lsls r2, r3 + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + 800086a: 481d ldr r0, [pc, #116] ; (80008e0 <NVIC_SetPriority+0xd4>) + 800086c: 1dfb adds r3, r7, #7 + 800086e: 781b ldrb r3, [r3, #0] + 8000870: 001c movs r4, r3 + 8000872: 230f movs r3, #15 + 8000874: 4023 ands r3, r4 + 8000876: 3b08 subs r3, #8 + 8000878: 089b lsrs r3, r3, #2 + 800087a: 430a orrs r2, r1 + 800087c: 3306 adds r3, #6 + 800087e: 009b lsls r3, r3, #2 + 8000880: 18c3 adds r3, r0, r3 + 8000882: 3304 adds r3, #4 + 8000884: 601a str r2, [r3, #0] +} + 8000886: e027 b.n 80008d8 <NVIC_SetPriority+0xcc> + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + 8000888: 4a16 ldr r2, [pc, #88] ; (80008e4 <NVIC_SetPriority+0xd8>) + 800088a: 1dfb adds r3, r7, #7 + 800088c: 781b ldrb r3, [r3, #0] + 800088e: b25b sxtb r3, r3 + 8000890: 089b lsrs r3, r3, #2 + 8000892: 33c0 adds r3, #192 ; 0xc0 + 8000894: 009b lsls r3, r3, #2 + 8000896: 589b ldr r3, [r3, r2] + 8000898: 1dfa adds r2, r7, #7 + 800089a: 7812 ldrb r2, [r2, #0] + 800089c: 0011 movs r1, r2 + 800089e: 2203 movs r2, #3 + 80008a0: 400a ands r2, r1 + 80008a2: 00d2 lsls r2, r2, #3 + 80008a4: 21ff movs r1, #255 ; 0xff + 80008a6: 4091 lsls r1, r2 + 80008a8: 000a movs r2, r1 + 80008aa: 43d2 mvns r2, r2 + 80008ac: 401a ands r2, r3 + 80008ae: 0011 movs r1, r2 + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + 80008b0: 683b ldr r3, [r7, #0] + 80008b2: 019b lsls r3, r3, #6 + 80008b4: 22ff movs r2, #255 ; 0xff + 80008b6: 401a ands r2, r3 + 80008b8: 1dfb adds r3, r7, #7 + 80008ba: 781b ldrb r3, [r3, #0] + 80008bc: 0018 movs r0, r3 + 80008be: 2303 movs r3, #3 + 80008c0: 4003 ands r3, r0 + 80008c2: 00db lsls r3, r3, #3 + 80008c4: 409a lsls r2, r3 + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + 80008c6: 4807 ldr r0, [pc, #28] ; (80008e4 <NVIC_SetPriority+0xd8>) + 80008c8: 1dfb adds r3, r7, #7 + 80008ca: 781b ldrb r3, [r3, #0] + 80008cc: b25b sxtb r3, r3 + 80008ce: 089b lsrs r3, r3, #2 + 80008d0: 430a orrs r2, r1 + 80008d2: 33c0 adds r3, #192 ; 0xc0 + 80008d4: 009b lsls r3, r3, #2 + 80008d6: 501a str r2, [r3, r0] +} + 80008d8: 46c0 nop ; (mov r8, r8) + 80008da: 46bd mov sp, r7 + 80008dc: b003 add sp, #12 + 80008de: bd90 pop {r4, r7, pc} + 80008e0: e000ed00 .word 0xe000ed00 + 80008e4: e000e100 .word 0xe000e100 + +080008e8 <usart_dma_init>: + +volatile struct dma_tx_buf usart_tx_buf; + +static void usart_schedule_dma(); + +void usart_dma_init() { + 80008e8: b580 push {r7, lr} + 80008ea: af00 add r7, sp, #0 + usart_tx_buf.xfr_start = -1, + 80008ec: 4b17 ldr r3, [pc, #92] ; (800094c <usart_dma_init+0x64>) + 80008ee: 2201 movs r2, #1 + 80008f0: 4252 negs r2, r2 + 80008f2: 601a str r2, [r3, #0] + usart_tx_buf.xfr_end = 0, + 80008f4: 4b15 ldr r3, [pc, #84] ; (800094c <usart_dma_init+0x64>) + 80008f6: 2200 movs r2, #0 + 80008f8: 605a str r2, [r3, #4] + usart_tx_buf.wr_pos = 0, + 80008fa: 4b14 ldr r3, [pc, #80] ; (800094c <usart_dma_init+0x64>) + 80008fc: 2200 movs r2, #0 + 80008fe: 609a str r2, [r3, #8] + + /* Configure DMA 1 Channel 2 to handle uart transmission */ + DMA1_Channel2->CPAR = (unsigned int)&(USART1->TDR); + 8000900: 4b13 ldr r3, [pc, #76] ; (8000950 <usart_dma_init+0x68>) + 8000902: 4a14 ldr r2, [pc, #80] ; (8000954 <usart_dma_init+0x6c>) + 8000904: 609a str r2, [r3, #8] + DMA1_Channel2->CCR = (0<<DMA_CCR_PL_Pos) + 8000906: 4b12 ldr r3, [pc, #72] ; (8000950 <usart_dma_init+0x68>) + 8000908: 2292 movs r2, #146 ; 0x92 + 800090a: 601a str r2, [r3, #0] + | (0<<DMA_CCR_PSIZE_Pos) /* 8 bit */ + | DMA_CCR_MINC + | DMA_CCR_TCIE; /* Enable transfer complete interrupt. */ + + /* triggered on transfer completion. We use this to process the ADC data */ + NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); + 800090c: 200a movs r0, #10 + 800090e: f7ff ff4f bl 80007b0 <NVIC_EnableIRQ> + NVIC_SetPriority(DMA1_Channel2_3_IRQn, 1<<5); + 8000912: 2120 movs r1, #32 + 8000914: 200a movs r0, #10 + 8000916: f7ff ff79 bl 800080c <NVIC_SetPriority> + + USART1->CR1 = /* 8-bit -> M1, M0 clear */ + 800091a: 4b0f ldr r3, [pc, #60] ; (8000958 <usart_dma_init+0x70>) + 800091c: 4a0f ldr r2, [pc, #60] ; (800095c <usart_dma_init+0x74>) + 800091e: 601a str r2, [r3, #0] + | USART_CR1_RXNEIE /* Enable receive interrupt */ + /* other interrupts clear */ + | USART_CR1_TE + | USART_CR1_RE; + /* Set divider for 1MBd @48MHz system clock. */ + USART1->BRR = 48; + 8000920: 4b0d ldr r3, [pc, #52] ; (8000958 <usart_dma_init+0x70>) + 8000922: 2230 movs r2, #48 ; 0x30 + 8000924: 60da str r2, [r3, #12] + + USART1->CR2 = USART_CR2_TXINV | USART_CR2_RXINV; + 8000926: 4b0c ldr r3, [pc, #48] ; (8000958 <usart_dma_init+0x70>) + 8000928: 22c0 movs r2, #192 ; 0xc0 + 800092a: 0292 lsls r2, r2, #10 + 800092c: 605a str r2, [r3, #4] + + USART1->CR3 |= USART_CR3_DMAT; /* TX DMA enable */ + 800092e: 4b0a ldr r3, [pc, #40] ; (8000958 <usart_dma_init+0x70>) + 8000930: 689a ldr r2, [r3, #8] + 8000932: 4b09 ldr r3, [pc, #36] ; (8000958 <usart_dma_init+0x70>) + 8000934: 2180 movs r1, #128 ; 0x80 + 8000936: 430a orrs r2, r1 + 8000938: 609a str r2, [r3, #8] + /* Enable receive interrupt */ + //NVIC_EnableIRQ(USART1_IRQn); + //NVIC_SetPriority(USART1_IRQn, 1); + + /* And... go! */ + USART1->CR1 |= USART_CR1_UE; + 800093a: 4b07 ldr r3, [pc, #28] ; (8000958 <usart_dma_init+0x70>) + 800093c: 681a ldr r2, [r3, #0] + 800093e: 4b06 ldr r3, [pc, #24] ; (8000958 <usart_dma_init+0x70>) + 8000940: 2101 movs r1, #1 + 8000942: 430a orrs r2, r1 + 8000944: 601a str r2, [r3, #0] +} + 8000946: 46c0 nop ; (mov r8, r8) + 8000948: 46bd mov sp, r7 + 800094a: bd80 pop {r7, pc} + 800094c: 200008c8 .word 0x200008c8 + 8000950: 4002001c .word 0x4002001c + 8000954: 40013828 .word 0x40013828 + 8000958: 40013800 .word 0x40013800 + 800095c: 0000202c .word 0x0000202c + +08000960 <usart_schedule_dma>: + +void usart_schedule_dma() { + 8000960: b580 push {r7, lr} + 8000962: b084 sub sp, #16 + 8000964: af00 add r7, sp, #0 + /* This function is only called when the DMA channel is disabled. This means we don't have to guard it in IRQ + * disables. */ + volatile struct dma_tx_buf *buf = &usart_tx_buf; + 8000966: 4b19 ldr r3, [pc, #100] ; (80009cc <usart_schedule_dma+0x6c>) + 8000968: 60bb str r3, [r7, #8] + + size_t xfr_len, xfr_start = buf->xfr_end; + 800096a: 68bb ldr r3, [r7, #8] + 800096c: 685b ldr r3, [r3, #4] + 800096e: 607b str r3, [r7, #4] + if (buf->wr_pos > xfr_start) /* no wraparound */ + 8000970: 68bb ldr r3, [r7, #8] + 8000972: 689b ldr r3, [r3, #8] + 8000974: 687a ldr r2, [r7, #4] + 8000976: 429a cmp r2, r3 + 8000978: d205 bcs.n 8000986 <usart_schedule_dma+0x26> + xfr_len = buf->wr_pos - xfr_start; + 800097a: 68bb ldr r3, [r7, #8] + 800097c: 689a ldr r2, [r3, #8] + 800097e: 687b ldr r3, [r7, #4] + 8000980: 1ad3 subs r3, r2, r3 + 8000982: 60fb str r3, [r7, #12] + 8000984: e004 b.n 8000990 <usart_schedule_dma+0x30> + else /* wraparound */ + xfr_len = sizeof(buf->data) - xfr_start; /* schedule transfer until end of buffer */ + 8000986: 687b ldr r3, [r7, #4] + 8000988: 2280 movs r2, #128 ; 0x80 + 800098a: 0052 lsls r2, r2, #1 + 800098c: 1ad3 subs r3, r2, r3 + 800098e: 60fb str r3, [r7, #12] + + buf->xfr_start = xfr_start; + 8000990: 68bb ldr r3, [r7, #8] + 8000992: 687a ldr r2, [r7, #4] + 8000994: 601a str r2, [r3, #0] + buf->xfr_end = (xfr_start + xfr_len) % sizeof(buf->data); /* handle wraparound */ + 8000996: 687a ldr r2, [r7, #4] + 8000998: 68fb ldr r3, [r7, #12] + 800099a: 18d3 adds r3, r2, r3 + 800099c: 22ff movs r2, #255 ; 0xff + 800099e: 401a ands r2, r3 + 80009a0: 68bb ldr r3, [r7, #8] + 80009a2: 605a str r2, [r3, #4] + + /* initiate transmission of new buffer */ + DMA1_Channel2->CMAR = (uint32_t)(buf->data + xfr_start); + 80009a4: 68bb ldr r3, [r7, #8] + 80009a6: 330c adds r3, #12 + 80009a8: 001a movs r2, r3 + 80009aa: 687b ldr r3, [r7, #4] + 80009ac: 18d2 adds r2, r2, r3 + 80009ae: 4b08 ldr r3, [pc, #32] ; (80009d0 <usart_schedule_dma+0x70>) + 80009b0: 60da str r2, [r3, #12] + DMA1_Channel2->CNDTR = xfr_len; + 80009b2: 4b07 ldr r3, [pc, #28] ; (80009d0 <usart_schedule_dma+0x70>) + 80009b4: 68fa ldr r2, [r7, #12] + 80009b6: 605a str r2, [r3, #4] + DMA1_Channel2->CCR |= DMA_CCR_EN; + 80009b8: 4b05 ldr r3, [pc, #20] ; (80009d0 <usart_schedule_dma+0x70>) + 80009ba: 681a ldr r2, [r3, #0] + 80009bc: 4b04 ldr r3, [pc, #16] ; (80009d0 <usart_schedule_dma+0x70>) + 80009be: 2101 movs r1, #1 + 80009c0: 430a orrs r2, r1 + 80009c2: 601a str r2, [r3, #0] +} + 80009c4: 46c0 nop ; (mov r8, r8) + 80009c6: 46bd mov sp, r7 + 80009c8: b004 add sp, #16 + 80009ca: bd80 pop {r7, pc} + 80009cc: 200008c8 .word 0x200008c8 + 80009d0: 4002001c .word 0x4002001c + +080009d4 <usart_dma_fifo_push>: + +int usart_dma_fifo_push(volatile struct dma_tx_buf *buf, char c) { + 80009d4: b580 push {r7, lr} + 80009d6: b082 sub sp, #8 + 80009d8: af00 add r7, sp, #0 + 80009da: 6078 str r0, [r7, #4] + 80009dc: 000a movs r2, r1 + 80009de: 1cfb adds r3, r7, #3 + 80009e0: 701a strb r2, [r3, #0] + /* This function must be guarded by IRQ disable since the IRQ may schedule a new transfer and charge pos/start. */ + NVIC_DisableIRQ(DMA1_Channel2_3_IRQn); + 80009e2: 200a movs r0, #10 + 80009e4: f7ff fefa bl 80007dc <NVIC_DisableIRQ> + + if (buf->wr_pos == buf->xfr_start) { + 80009e8: 687b ldr r3, [r7, #4] + 80009ea: 689a ldr r2, [r3, #8] + 80009ec: 687b ldr r3, [r7, #4] + 80009ee: 681b ldr r3, [r3, #0] + 80009f0: 429a cmp r2, r3 + 80009f2: d105 bne.n 8000a00 <usart_dma_fifo_push+0x2c> + NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); + 80009f4: 200a movs r0, #10 + 80009f6: f7ff fedb bl 80007b0 <NVIC_EnableIRQ> + return -EBUSY; + 80009fa: 2310 movs r3, #16 + 80009fc: 425b negs r3, r3 + 80009fe: e011 b.n 8000a24 <usart_dma_fifo_push+0x50> + } + + buf->data[buf->wr_pos] = c; + 8000a00: 687b ldr r3, [r7, #4] + 8000a02: 689b ldr r3, [r3, #8] + 8000a04: 687a ldr r2, [r7, #4] + 8000a06: 18d3 adds r3, r2, r3 + 8000a08: 1cfa adds r2, r7, #3 + 8000a0a: 7812 ldrb r2, [r2, #0] + 8000a0c: 731a strb r2, [r3, #12] + buf->wr_pos = (buf->wr_pos + 1) % sizeof(buf->data); + 8000a0e: 687b ldr r3, [r7, #4] + 8000a10: 689b ldr r3, [r3, #8] + 8000a12: 3301 adds r3, #1 + 8000a14: 22ff movs r2, #255 ; 0xff + 8000a16: 401a ands r2, r3 + 8000a18: 687b ldr r3, [r7, #4] + 8000a1a: 609a str r2, [r3, #8] + + NVIC_EnableIRQ(DMA1_Channel2_3_IRQn); + 8000a1c: 200a movs r0, #10 + 8000a1e: f7ff fec7 bl 80007b0 <NVIC_EnableIRQ> + return 0; + 8000a22: 2300 movs r3, #0 +} + 8000a24: 0018 movs r0, r3 + 8000a26: 46bd mov sp, r7 + 8000a28: b002 add sp, #8 + 8000a2a: bd80 pop {r7, pc} + +08000a2c <usart_putc>: + +void usart_putc(char c) { + 8000a2c: b580 push {r7, lr} + 8000a2e: b082 sub sp, #8 + 8000a30: af00 add r7, sp, #0 + 8000a32: 0002 movs r2, r0 + 8000a34: 1dfb adds r3, r7, #7 + 8000a36: 701a strb r2, [r3, #0] + /* push char to fifo, busy-loop if stalled to wait for USART to empty fifo via DMA */ + while (usart_dma_fifo_push(&usart_tx_buf, c) == -EBUSY) { + 8000a38: 46c0 nop ; (mov r8, r8) + 8000a3a: 1dfb adds r3, r7, #7 + 8000a3c: 781a ldrb r2, [r3, #0] + 8000a3e: 4b06 ldr r3, [pc, #24] ; (8000a58 <usart_putc+0x2c>) + 8000a40: 0011 movs r1, r2 + 8000a42: 0018 movs r0, r3 + 8000a44: f7ff ffc6 bl 80009d4 <usart_dma_fifo_push> + 8000a48: 0003 movs r3, r0 + 8000a4a: 3310 adds r3, #16 + 8000a4c: d0f5 beq.n 8000a3a <usart_putc+0xe> + /* idle */ + } +} + 8000a4e: 46c0 nop ; (mov r8, r8) + 8000a50: 46c0 nop ; (mov r8, r8) + 8000a52: 46bd mov sp, r7 + 8000a54: b002 add sp, #8 + 8000a56: bd80 pop {r7, pc} + 8000a58: 200008c8 .word 0x200008c8 + +08000a5c <DMA1_Channel2_3_IRQHandler>: + +void DMA1_Channel2_3_IRQHandler(void) { + 8000a5c: b580 push {r7, lr} + 8000a5e: af00 add r7, sp, #0 + /* Transfer complete */ + DMA1->IFCR |= DMA_IFCR_CTCIF2; + 8000a60: 4b0b ldr r3, [pc, #44] ; (8000a90 <DMA1_Channel2_3_IRQHandler+0x34>) + 8000a62: 685a ldr r2, [r3, #4] + 8000a64: 4b0a ldr r3, [pc, #40] ; (8000a90 <DMA1_Channel2_3_IRQHandler+0x34>) + 8000a66: 2120 movs r1, #32 + 8000a68: 430a orrs r2, r1 + 8000a6a: 605a str r2, [r3, #4] + + DMA1_Channel2->CCR &= ~DMA_CCR_EN; + 8000a6c: 4b09 ldr r3, [pc, #36] ; (8000a94 <DMA1_Channel2_3_IRQHandler+0x38>) + 8000a6e: 681a ldr r2, [r3, #0] + 8000a70: 4b08 ldr r3, [pc, #32] ; (8000a94 <DMA1_Channel2_3_IRQHandler+0x38>) + 8000a72: 2101 movs r1, #1 + 8000a74: 438a bics r2, r1 + 8000a76: 601a str r2, [r3, #0] + if (usart_tx_buf.wr_pos != usart_tx_buf.xfr_end) /* buffer not empty */ + 8000a78: 4b07 ldr r3, [pc, #28] ; (8000a98 <DMA1_Channel2_3_IRQHandler+0x3c>) + 8000a7a: 689a ldr r2, [r3, #8] + 8000a7c: 4b06 ldr r3, [pc, #24] ; (8000a98 <DMA1_Channel2_3_IRQHandler+0x3c>) + 8000a7e: 685b ldr r3, [r3, #4] + 8000a80: 429a cmp r2, r3 + 8000a82: d001 beq.n 8000a88 <DMA1_Channel2_3_IRQHandler+0x2c> + usart_schedule_dma(); + 8000a84: f7ff ff6c bl 8000960 <usart_schedule_dma> +} + 8000a88: 46c0 nop ; (mov r8, r8) + 8000a8a: 46bd mov sp, r7 + 8000a8c: bd80 pop {r7, pc} + 8000a8e: 46c0 nop ; (mov r8, r8) + 8000a90: 40020000 .word 0x40020000 + 8000a94: 4002001c .word 0x4002001c + 8000a98: 200008c8 .word 0x200008c8 + +08000a9c <usart_send_packet>: + +void usart_send_packet(const uint8_t *data, size_t len) { + 8000a9c: b580 push {r7, lr} + 8000a9e: b082 sub sp, #8 + 8000aa0: af00 add r7, sp, #0 + 8000aa2: 6078 str r0, [r7, #4] + 8000aa4: 6039 str r1, [r7, #0] + /* ignore return value as putf is blocking and always succeeds */ + (void)cobs_encode_usart((char *)data, len); + 8000aa6: 683a ldr r2, [r7, #0] + 8000aa8: 687b ldr r3, [r7, #4] + 8000aaa: 0011 movs r1, r2 + 8000aac: 0018 movs r0, r3 + 8000aae: f000 f870 bl 8000b92 <cobs_encode_usart> + + /* If the DMA stream is idle right now, schedule a transfer */ + if (!(DMA1_Channel2->CCR & DMA_CCR_EN)) + 8000ab2: 4b05 ldr r3, [pc, #20] ; (8000ac8 <usart_send_packet+0x2c>) + 8000ab4: 681b ldr r3, [r3, #0] + 8000ab6: 2201 movs r2, #1 + 8000ab8: 4013 ands r3, r2 + 8000aba: d101 bne.n 8000ac0 <usart_send_packet+0x24> + usart_schedule_dma(); + 8000abc: f7ff ff50 bl 8000960 <usart_schedule_dma> +} + 8000ac0: 46c0 nop ; (mov r8, r8) + 8000ac2: 46bd mov sp, r7 + 8000ac4: b002 add sp, #8 + 8000ac6: bd80 pop {r7, pc} + 8000ac8: 4002001c .word 0x4002001c + +08000acc <cobs_encode>: + @ ensures \result == -1; + @ + @ complete behaviors; + @ disjoint behaviors; + @*/ +ssize_t cobs_encode(char *dst, size_t dstlen, char *src, size_t srclen) { + 8000acc: b580 push {r7, lr} + 8000ace: b088 sub sp, #32 + 8000ad0: af00 add r7, sp, #0 + 8000ad2: 60f8 str r0, [r7, #12] + 8000ad4: 60b9 str r1, [r7, #8] + 8000ad6: 607a str r2, [r7, #4] + 8000ad8: 603b str r3, [r7, #0] + if (dstlen > 65535 || srclen > 254) + 8000ada: 68ba ldr r2, [r7, #8] + 8000adc: 2380 movs r3, #128 ; 0x80 + 8000ade: 025b lsls r3, r3, #9 + 8000ae0: 429a cmp r2, r3 + 8000ae2: d202 bcs.n 8000aea <cobs_encode+0x1e> + 8000ae4: 683b ldr r3, [r7, #0] + 8000ae6: 2bfe cmp r3, #254 ; 0xfe + 8000ae8: d902 bls.n 8000af0 <cobs_encode+0x24> + return -1; + 8000aea: 2301 movs r3, #1 + 8000aec: 425b negs r3, r3 + 8000aee: e04c b.n 8000b8a <cobs_encode+0xbe> + //@ assert 0 <= dstlen <= 65535 && 0 <= srclen <= 254; + + if (dstlen < srclen+2) + 8000af0: 683b ldr r3, [r7, #0] + 8000af2: 3302 adds r3, #2 + 8000af4: 68ba ldr r2, [r7, #8] + 8000af6: 429a cmp r2, r3 + 8000af8: d202 bcs.n 8000b00 <cobs_encode+0x34> + return -1; + 8000afa: 2301 movs r3, #1 + 8000afc: 425b negs r3, r3 + 8000afe: e044 b.n 8000b8a <cobs_encode+0xbe> + //@ assert 0 <= srclen < srclen+2 <= dstlen; + + size_t p = 0; + 8000b00: 2300 movs r3, #0 + 8000b02: 61fb str r3, [r7, #28] + @ loop invariant \forall integer i; 0 <= i < p ==> dst[i] != 0; + @ loop invariant \forall integer i; 0 < i < p ==> (src[i-1] != 0 ==> dst[i] == src[i-1]); + @ loop assigns p, dst[0..srclen+1]; + @ loop variant srclen-p+1; + @*/ + while (p <= srclen) { + 8000b04: e036 b.n 8000b74 <cobs_encode+0xa8> + + char val; + if (p != 0 && src[p-1] != 0) { + 8000b06: 69fb ldr r3, [r7, #28] + 8000b08: 2b00 cmp r3, #0 + 8000b0a: d00f beq.n 8000b2c <cobs_encode+0x60> + 8000b0c: 69fb ldr r3, [r7, #28] + 8000b0e: 3b01 subs r3, #1 + 8000b10: 687a ldr r2, [r7, #4] + 8000b12: 18d3 adds r3, r2, r3 + 8000b14: 781b ldrb r3, [r3, #0] + 8000b16: 2b00 cmp r3, #0 + 8000b18: d008 beq.n 8000b2c <cobs_encode+0x60> + val = src[p-1]; + 8000b1a: 69fb ldr r3, [r7, #28] + 8000b1c: 3b01 subs r3, #1 + 8000b1e: 687a ldr r2, [r7, #4] + 8000b20: 18d2 adds r2, r2, r3 + 8000b22: 231b movs r3, #27 + 8000b24: 18fb adds r3, r7, r3 + 8000b26: 7812 ldrb r2, [r2, #0] + 8000b28: 701a strb r2, [r3, #0] + 8000b2a: e019 b.n 8000b60 <cobs_encode+0x94> + + } else { + size_t q = p; + 8000b2c: 69fb ldr r3, [r7, #28] + 8000b2e: 617b str r3, [r7, #20] + /*@ loop invariant 0 <= p <= q <= srclen; + @ loop invariant \forall integer i; p <= i < q ==> src[i] != 0; + @ loop assigns q; + @ loop variant srclen-q; + @*/ + while (q < srclen && src[q] != 0) + 8000b30: e002 b.n 8000b38 <cobs_encode+0x6c> + q++; + 8000b32: 697b ldr r3, [r7, #20] + 8000b34: 3301 adds r3, #1 + 8000b36: 617b str r3, [r7, #20] + while (q < srclen && src[q] != 0) + 8000b38: 697a ldr r2, [r7, #20] + 8000b3a: 683b ldr r3, [r7, #0] + 8000b3c: 429a cmp r2, r3 + 8000b3e: d205 bcs.n 8000b4c <cobs_encode+0x80> + 8000b40: 687a ldr r2, [r7, #4] + 8000b42: 697b ldr r3, [r7, #20] + 8000b44: 18d3 adds r3, r2, r3 + 8000b46: 781b ldrb r3, [r3, #0] + 8000b48: 2b00 cmp r3, #0 + 8000b4a: d1f2 bne.n 8000b32 <cobs_encode+0x66> + //@ assert q == srclen || src[q] == 0; + //@ assert q <= srclen <= 254; + val = (char)q-p+1; + 8000b4c: 697b ldr r3, [r7, #20] + 8000b4e: b2da uxtb r2, r3 + 8000b50: 69fb ldr r3, [r7, #28] + 8000b52: b2db uxtb r3, r3 + 8000b54: 1ad3 subs r3, r2, r3 + 8000b56: b2da uxtb r2, r3 + 8000b58: 231b movs r3, #27 + 8000b5a: 18fb adds r3, r7, r3 + 8000b5c: 3201 adds r2, #1 + 8000b5e: 701a strb r2, [r3, #0] + //@ assert val != 0; + } + + dst[p] = val; + 8000b60: 68fa ldr r2, [r7, #12] + 8000b62: 69fb ldr r3, [r7, #28] + 8000b64: 18d3 adds r3, r2, r3 + 8000b66: 221b movs r2, #27 + 8000b68: 18ba adds r2, r7, r2 + 8000b6a: 7812 ldrb r2, [r2, #0] + 8000b6c: 701a strb r2, [r3, #0] + p++; + 8000b6e: 69fb ldr r3, [r7, #28] + 8000b70: 3301 adds r3, #1 + 8000b72: 61fb str r3, [r7, #28] + while (p <= srclen) { + 8000b74: 69fa ldr r2, [r7, #28] + 8000b76: 683b ldr r3, [r7, #0] + 8000b78: 429a cmp r2, r3 + 8000b7a: d9c4 bls.n 8000b06 <cobs_encode+0x3a> + } + + dst[p] = 0; + 8000b7c: 68fa ldr r2, [r7, #12] + 8000b7e: 69fb ldr r3, [r7, #28] + 8000b80: 18d3 adds r3, r2, r3 + 8000b82: 2200 movs r2, #0 + 8000b84: 701a strb r2, [r3, #0] + //@ assert p == srclen+1; + + return srclen+2; + 8000b86: 683b ldr r3, [r7, #0] + 8000b88: 3302 adds r3, #2 +} + 8000b8a: 0018 movs r0, r3 + 8000b8c: 46bd mov sp, r7 + 8000b8e: b008 add sp, #32 + 8000b90: bd80 pop {r7, pc} + +08000b92 <cobs_encode_usart>: + +int cobs_encode_usart(char *src, size_t srclen) { + 8000b92: b580 push {r7, lr} + 8000b94: b086 sub sp, #24 + 8000b96: af00 add r7, sp, #0 + 8000b98: 6078 str r0, [r7, #4] + 8000b9a: 6039 str r1, [r7, #0] + if (srclen > 254) + 8000b9c: 683b ldr r3, [r7, #0] + 8000b9e: 2bfe cmp r3, #254 ; 0xfe + 8000ba0: d902 bls.n 8000ba8 <cobs_encode_usart+0x16> + return -1; + 8000ba2: 2301 movs r3, #1 + 8000ba4: 425b negs r3, r3 + 8000ba6: e040 b.n 8000c2a <cobs_encode_usart+0x98> + //@ assert 0 <= srclen <= 254; + + size_t p = 0; + 8000ba8: 2300 movs r3, #0 + 8000baa: 617b str r3, [r7, #20] + /*@ loop invariant 0 <= p <= srclen+1; + @ loop assigns p; + @ loop variant srclen-p+1; + @*/ + while (p <= srclen) { + 8000bac: e035 b.n 8000c1a <cobs_encode_usart+0x88> + + char val; + if (p != 0 && src[p-1] != 0) { + 8000bae: 697b ldr r3, [r7, #20] + 8000bb0: 2b00 cmp r3, #0 + 8000bb2: d00f beq.n 8000bd4 <cobs_encode_usart+0x42> + 8000bb4: 697b ldr r3, [r7, #20] + 8000bb6: 3b01 subs r3, #1 + 8000bb8: 687a ldr r2, [r7, #4] + 8000bba: 18d3 adds r3, r2, r3 + 8000bbc: 781b ldrb r3, [r3, #0] + 8000bbe: 2b00 cmp r3, #0 + 8000bc0: d008 beq.n 8000bd4 <cobs_encode_usart+0x42> + val = src[p-1]; + 8000bc2: 697b ldr r3, [r7, #20] + 8000bc4: 3b01 subs r3, #1 + 8000bc6: 687a ldr r2, [r7, #4] + 8000bc8: 18d2 adds r2, r2, r3 + 8000bca: 2313 movs r3, #19 + 8000bcc: 18fb adds r3, r7, r3 + 8000bce: 7812 ldrb r2, [r2, #0] + 8000bd0: 701a strb r2, [r3, #0] + 8000bd2: e019 b.n 8000c08 <cobs_encode_usart+0x76> + + } else { + size_t q = p; + 8000bd4: 697b ldr r3, [r7, #20] + 8000bd6: 60fb str r3, [r7, #12] + /*@ loop invariant 0 <= p <= q <= srclen; + @ loop invariant \forall integer i; p <= i < q ==> src[i] != 0; + @ loop assigns q; + @ loop variant srclen-q; + @*/ + while (q < srclen && src[q] != 0) + 8000bd8: e002 b.n 8000be0 <cobs_encode_usart+0x4e> + q++; + 8000bda: 68fb ldr r3, [r7, #12] + 8000bdc: 3301 adds r3, #1 + 8000bde: 60fb str r3, [r7, #12] + while (q < srclen && src[q] != 0) + 8000be0: 68fa ldr r2, [r7, #12] + 8000be2: 683b ldr r3, [r7, #0] + 8000be4: 429a cmp r2, r3 + 8000be6: d205 bcs.n 8000bf4 <cobs_encode_usart+0x62> + 8000be8: 687a ldr r2, [r7, #4] + 8000bea: 68fb ldr r3, [r7, #12] + 8000bec: 18d3 adds r3, r2, r3 + 8000bee: 781b ldrb r3, [r3, #0] + 8000bf0: 2b00 cmp r3, #0 + 8000bf2: d1f2 bne.n 8000bda <cobs_encode_usart+0x48> + //@ assert q == srclen || src[q] == 0; + //@ assert q <= srclen <= 254; + val = (char)q-p+1; + 8000bf4: 68fb ldr r3, [r7, #12] + 8000bf6: b2da uxtb r2, r3 + 8000bf8: 697b ldr r3, [r7, #20] + 8000bfa: b2db uxtb r3, r3 + 8000bfc: 1ad3 subs r3, r2, r3 + 8000bfe: b2da uxtb r2, r3 + 8000c00: 2313 movs r3, #19 + 8000c02: 18fb adds r3, r7, r3 + 8000c04: 3201 adds r2, #1 + 8000c06: 701a strb r2, [r3, #0] + //@ assert val != 0; + } + + usart_putc(val); + 8000c08: 2313 movs r3, #19 + 8000c0a: 18fb adds r3, r7, r3 + 8000c0c: 781b ldrb r3, [r3, #0] + 8000c0e: 0018 movs r0, r3 + 8000c10: f7ff ff0c bl 8000a2c <usart_putc> + p++; + 8000c14: 697b ldr r3, [r7, #20] + 8000c16: 3301 adds r3, #1 + 8000c18: 617b str r3, [r7, #20] + while (p <= srclen) { + 8000c1a: 697a ldr r2, [r7, #20] + 8000c1c: 683b ldr r3, [r7, #0] + 8000c1e: 429a cmp r2, r3 + 8000c20: d9c5 bls.n 8000bae <cobs_encode_usart+0x1c> + } + + usart_putc(0); + 8000c22: 2000 movs r0, #0 + 8000c24: f7ff ff02 bl 8000a2c <usart_putc> + //@ assert p == srclen+1; + + return 0; + 8000c28: 2300 movs r3, #0 +} + 8000c2a: 0018 movs r0, r3 + 8000c2c: 46bd mov sp, r7 + 8000c2e: b006 add sp, #24 + 8000c30: bd80 pop {r7, pc} + +08000c32 <cobs_decode>: + @ ensures \result == -1; + @ + @ complete behaviors; + @ disjoint behaviors; + @*/ +ssize_t cobs_decode(char *dst, size_t dstlen, char *src, size_t srclen) { + 8000c32: b580 push {r7, lr} + 8000c34: b088 sub sp, #32 + 8000c36: af00 add r7, sp, #0 + 8000c38: 60f8 str r0, [r7, #12] + 8000c3a: 60b9 str r1, [r7, #8] + 8000c3c: 607a str r2, [r7, #4] + 8000c3e: 603b str r3, [r7, #0] + if (dstlen > 65535 || srclen > 65535) + 8000c40: 68ba ldr r2, [r7, #8] + 8000c42: 2380 movs r3, #128 ; 0x80 + 8000c44: 025b lsls r3, r3, #9 + 8000c46: 429a cmp r2, r3 + 8000c48: d204 bcs.n 8000c54 <cobs_decode+0x22> + 8000c4a: 683a ldr r2, [r7, #0] + 8000c4c: 2380 movs r3, #128 ; 0x80 + 8000c4e: 025b lsls r3, r3, #9 + 8000c50: 429a cmp r2, r3 + 8000c52: d302 bcc.n 8000c5a <cobs_decode+0x28> + return -1; + 8000c54: 2301 movs r3, #1 + 8000c56: 425b negs r3, r3 + 8000c58: e052 b.n 8000d00 <cobs_decode+0xce> + + if (srclen < 1) + 8000c5a: 683b ldr r3, [r7, #0] + 8000c5c: 2b00 cmp r3, #0 + 8000c5e: d102 bne.n 8000c66 <cobs_decode+0x34> + return -1; + 8000c60: 2301 movs r3, #1 + 8000c62: 425b negs r3, r3 + 8000c64: e04c b.n 8000d00 <cobs_decode+0xce> + + if (dstlen < srclen) + 8000c66: 68ba ldr r2, [r7, #8] + 8000c68: 683b ldr r3, [r7, #0] + 8000c6a: 429a cmp r2, r3 + 8000c6c: d202 bcs.n 8000c74 <cobs_decode+0x42> + return -1; + 8000c6e: 2301 movs r3, #1 + 8000c70: 425b negs r3, r3 + 8000c72: e045 b.n 8000d00 <cobs_decode+0xce> + + size_t p = 1; + 8000c74: 2301 movs r3, #1 + 8000c76: 61fb str r3, [r7, #28] + size_t c = (unsigned char)src[0]; + 8000c78: 687b ldr r3, [r7, #4] + 8000c7a: 781b ldrb r3, [r3, #0] + 8000c7c: 61bb str r3, [r7, #24] + //@ assert 0 <= c < 256; + //@ assert 0 <= c; + //@ assert c < 256; + if (c == 0) + 8000c7e: 69bb ldr r3, [r7, #24] + 8000c80: 2b00 cmp r3, #0 + 8000c82: d124 bne.n 8000cce <cobs_decode+0x9c> + return -2; /* invalid framing. An empty frame would be [...] 00 01 00, not [...] 00 00 */ + 8000c84: 2302 movs r3, #2 + 8000c86: 425b negs r3, r3 + 8000c88: e03a b.n 8000d00 <cobs_decode+0xce> + @ loop assigns dst[0..dstlen-1], p, c; + @ loop variant srclen-p; + @*/ + while (p < srclen && src[p]) { + char val; + c--; + 8000c8a: 69bb ldr r3, [r7, #24] + 8000c8c: 3b01 subs r3, #1 + 8000c8e: 61bb str r3, [r7, #24] + + //@ assert src[p] != 0; + if (c == 0) { + 8000c90: 69bb ldr r3, [r7, #24] + 8000c92: 2b00 cmp r3, #0 + 8000c94: d109 bne.n 8000caa <cobs_decode+0x78> + c = (unsigned char)src[p]; + 8000c96: 687a ldr r2, [r7, #4] + 8000c98: 69fb ldr r3, [r7, #28] + 8000c9a: 18d3 adds r3, r2, r3 + 8000c9c: 781b ldrb r3, [r3, #0] + 8000c9e: 61bb str r3, [r7, #24] + val = 0; + 8000ca0: 2317 movs r3, #23 + 8000ca2: 18fb adds r3, r7, r3 + 8000ca4: 2200 movs r2, #0 + 8000ca6: 701a strb r2, [r3, #0] + 8000ca8: e006 b.n 8000cb8 <cobs_decode+0x86> + } else { + val = src[p]; + 8000caa: 687a ldr r2, [r7, #4] + 8000cac: 69fb ldr r3, [r7, #28] + 8000cae: 18d2 adds r2, r2, r3 + 8000cb0: 2317 movs r3, #23 + 8000cb2: 18fb adds r3, r7, r3 + 8000cb4: 7812 ldrb r2, [r2, #0] + 8000cb6: 701a strb r2, [r3, #0] + } + + //@ assert 0 <= p-1 <= dstlen-1; + dst[p-1] = val; + 8000cb8: 69fb ldr r3, [r7, #28] + 8000cba: 3b01 subs r3, #1 + 8000cbc: 68fa ldr r2, [r7, #12] + 8000cbe: 18d3 adds r3, r2, r3 + 8000cc0: 2217 movs r2, #23 + 8000cc2: 18ba adds r2, r7, r2 + 8000cc4: 7812 ldrb r2, [r2, #0] + 8000cc6: 701a strb r2, [r3, #0] + p++; + 8000cc8: 69fb ldr r3, [r7, #28] + 8000cca: 3301 adds r3, #1 + 8000ccc: 61fb str r3, [r7, #28] + while (p < srclen && src[p]) { + 8000cce: 69fa ldr r2, [r7, #28] + 8000cd0: 683b ldr r3, [r7, #0] + 8000cd2: 429a cmp r2, r3 + 8000cd4: d205 bcs.n 8000ce2 <cobs_decode+0xb0> + 8000cd6: 687a ldr r2, [r7, #4] + 8000cd8: 69fb ldr r3, [r7, #28] + 8000cda: 18d3 adds r3, r2, r3 + 8000cdc: 781b ldrb r3, [r3, #0] + 8000cde: 2b00 cmp r3, #0 + 8000ce0: d1d3 bne.n 8000c8a <cobs_decode+0x58> + } + + if (p == srclen) + 8000ce2: 69fa ldr r2, [r7, #28] + 8000ce4: 683b ldr r3, [r7, #0] + 8000ce6: 429a cmp r2, r3 + 8000ce8: d102 bne.n 8000cf0 <cobs_decode+0xbe> + return -2; /* Invalid framing. The terminating null byte should always be present in the input buffer. */ + 8000cea: 2302 movs r3, #2 + 8000cec: 425b negs r3, r3 + 8000cee: e007 b.n 8000d00 <cobs_decode+0xce> + + if (c != 1) + 8000cf0: 69bb ldr r3, [r7, #24] + 8000cf2: 2b01 cmp r3, #1 + 8000cf4: d002 beq.n 8000cfc <cobs_decode+0xca> + return -3; /* Invalid framing. The skip counter does not hit the end of the frame. */ + 8000cf6: 2303 movs r3, #3 + 8000cf8: 425b negs r3, r3 + 8000cfa: e001 b.n 8000d00 <cobs_decode+0xce> + + //@ assert 0 < p <= srclen <= 65535; + //@ assert src[p] == 0; + //@ assert \forall integer i; 1 <= i < p ==> src[i] != 0; + return p-1; + 8000cfc: 69fb ldr r3, [r7, #28] + 8000cfe: 3b01 subs r3, #1 +} + 8000d00: 0018 movs r0, r3 + 8000d02: 46bd mov sp, r7 + 8000d04: b008 add sp, #32 + 8000d06: bd80 pop {r7, pc} + +08000d08 <cobs_decode_incremental_initialize>: + +void cobs_decode_incremental_initialize(struct cobs_decode_state *state) { + 8000d08: b580 push {r7, lr} + 8000d0a: b082 sub sp, #8 + 8000d0c: af00 add r7, sp, #0 + 8000d0e: 6078 str r0, [r7, #4] + state->p = 0; + 8000d10: 687b ldr r3, [r7, #4] + 8000d12: 2200 movs r2, #0 + 8000d14: 601a str r2, [r3, #0] + state->c = 0; + 8000d16: 687b ldr r3, [r7, #4] + 8000d18: 2200 movs r2, #0 + 8000d1a: 605a str r2, [r3, #4] +} + 8000d1c: 46c0 nop ; (mov r8, r8) + 8000d1e: 46bd mov sp, r7 + 8000d20: b002 add sp, #8 + 8000d22: bd80 pop {r7, pc} + +08000d24 <cobs_decode_incremental>: + +int cobs_decode_incremental(struct cobs_decode_state *state, char *dst, size_t dstlen, char src) { + 8000d24: b580 push {r7, lr} + 8000d26: b088 sub sp, #32 + 8000d28: af00 add r7, sp, #0 + 8000d2a: 60f8 str r0, [r7, #12] + 8000d2c: 60b9 str r1, [r7, #8] + 8000d2e: 607a str r2, [r7, #4] + 8000d30: 001a movs r2, r3 + 8000d32: 1cfb adds r3, r7, #3 + 8000d34: 701a strb r2, [r3, #0] + if (state->p == 0) { + 8000d36: 68fb ldr r3, [r7, #12] + 8000d38: 681b ldr r3, [r3, #0] + 8000d3a: 2b00 cmp r3, #0 + 8000d3c: d10e bne.n 8000d5c <cobs_decode_incremental+0x38> + if (src == 0) + 8000d3e: 1cfb adds r3, r7, #3 + 8000d40: 781b ldrb r3, [r3, #0] + 8000d42: 2b00 cmp r3, #0 + 8000d44: d054 beq.n 8000df0 <cobs_decode_incremental+0xcc> + goto empty_errout; /* invalid framing. An empty frame would be [...] 00 01 00, not [...] 00 00 */ + state->c = (unsigned char)src; + 8000d46: 1cfb adds r3, r7, #3 + 8000d48: 781a ldrb r2, [r3, #0] + 8000d4a: 68fb ldr r3, [r7, #12] + 8000d4c: 605a str r2, [r3, #4] + state->p++; + 8000d4e: 68fb ldr r3, [r7, #12] + 8000d50: 681b ldr r3, [r3, #0] + 8000d52: 1c5a adds r2, r3, #1 + 8000d54: 68fb ldr r3, [r7, #12] + 8000d56: 601a str r2, [r3, #0] + return 0; + 8000d58: 2300 movs r3, #0 + 8000d5a: e050 b.n 8000dfe <cobs_decode_incremental+0xda> + } + + if (!src) { + 8000d5c: 1cfb adds r3, r7, #3 + 8000d5e: 781b ldrb r3, [r3, #0] + 8000d60: 2b00 cmp r3, #0 + 8000d62: d10d bne.n 8000d80 <cobs_decode_incremental+0x5c> + if (state->c != 1) + 8000d64: 68fb ldr r3, [r7, #12] + 8000d66: 685b ldr r3, [r3, #4] + 8000d68: 2b01 cmp r3, #1 + 8000d6a: d139 bne.n 8000de0 <cobs_decode_incremental+0xbc> + goto errout; /* Invalid framing. The skip counter does not hit the end of the frame. */ + int rv = state->p-1; + 8000d6c: 68fb ldr r3, [r7, #12] + 8000d6e: 681b ldr r3, [r3, #0] + 8000d70: 3b01 subs r3, #1 + 8000d72: 617b str r3, [r7, #20] + cobs_decode_incremental_initialize(state); + 8000d74: 68fb ldr r3, [r7, #12] + 8000d76: 0018 movs r0, r3 + 8000d78: f7ff ffc6 bl 8000d08 <cobs_decode_incremental_initialize> + return rv; + 8000d7c: 697b ldr r3, [r7, #20] + 8000d7e: e03e b.n 8000dfe <cobs_decode_incremental+0xda> + } + + char val; + state->c--; + 8000d80: 68fb ldr r3, [r7, #12] + 8000d82: 685b ldr r3, [r3, #4] + 8000d84: 1e5a subs r2, r3, #1 + 8000d86: 68fb ldr r3, [r7, #12] + 8000d88: 605a str r2, [r3, #4] + + if (state->c == 0) { + 8000d8a: 68fb ldr r3, [r7, #12] + 8000d8c: 685b ldr r3, [r3, #4] + 8000d8e: 2b00 cmp r3, #0 + 8000d90: d108 bne.n 8000da4 <cobs_decode_incremental+0x80> + state->c = (unsigned char)src; + 8000d92: 1cfb adds r3, r7, #3 + 8000d94: 781a ldrb r2, [r3, #0] + 8000d96: 68fb ldr r3, [r7, #12] + 8000d98: 605a str r2, [r3, #4] + val = 0; + 8000d9a: 231f movs r3, #31 + 8000d9c: 18fb adds r3, r7, r3 + 8000d9e: 2200 movs r2, #0 + 8000da0: 701a strb r2, [r3, #0] + 8000da2: e004 b.n 8000dae <cobs_decode_incremental+0x8a> + } else { + val = src; + 8000da4: 231f movs r3, #31 + 8000da6: 18fb adds r3, r7, r3 + 8000da8: 1cfa adds r2, r7, #3 + 8000daa: 7812 ldrb r2, [r2, #0] + 8000dac: 701a strb r2, [r3, #0] + } + + size_t pos = state->p-1; + 8000dae: 68fb ldr r3, [r7, #12] + 8000db0: 681b ldr r3, [r3, #0] + 8000db2: 3b01 subs r3, #1 + 8000db4: 61bb str r3, [r7, #24] + if (pos >= dstlen) + 8000db6: 69ba ldr r2, [r7, #24] + 8000db8: 687b ldr r3, [r7, #4] + 8000dba: 429a cmp r2, r3 + 8000dbc: d302 bcc.n 8000dc4 <cobs_decode_incremental+0xa0> + return -2; /* output buffer too small */ + 8000dbe: 2302 movs r3, #2 + 8000dc0: 425b negs r3, r3 + 8000dc2: e01c b.n 8000dfe <cobs_decode_incremental+0xda> + dst[pos] = val; + 8000dc4: 68ba ldr r2, [r7, #8] + 8000dc6: 69bb ldr r3, [r7, #24] + 8000dc8: 18d3 adds r3, r2, r3 + 8000dca: 221f movs r2, #31 + 8000dcc: 18ba adds r2, r7, r2 + 8000dce: 7812 ldrb r2, [r2, #0] + 8000dd0: 701a strb r2, [r3, #0] + state->p++; + 8000dd2: 68fb ldr r3, [r7, #12] + 8000dd4: 681b ldr r3, [r3, #0] + 8000dd6: 1c5a adds r2, r3, #1 + 8000dd8: 68fb ldr r3, [r7, #12] + 8000dda: 601a str r2, [r3, #0] + return 0; + 8000ddc: 2300 movs r3, #0 + 8000dde: e00e b.n 8000dfe <cobs_decode_incremental+0xda> + goto errout; /* Invalid framing. The skip counter does not hit the end of the frame. */ + 8000de0: 46c0 nop ; (mov r8, r8) + +errout: + cobs_decode_incremental_initialize(state); + 8000de2: 68fb ldr r3, [r7, #12] + 8000de4: 0018 movs r0, r3 + 8000de6: f7ff ff8f bl 8000d08 <cobs_decode_incremental_initialize> + return -1; + 8000dea: 2301 movs r3, #1 + 8000dec: 425b negs r3, r3 + 8000dee: e006 b.n 8000dfe <cobs_decode_incremental+0xda> + goto empty_errout; /* invalid framing. An empty frame would be [...] 00 01 00, not [...] 00 00 */ + 8000df0: 46c0 nop ; (mov r8, r8) + +empty_errout: + cobs_decode_incremental_initialize(state); + 8000df2: 68fb ldr r3, [r7, #12] + 8000df4: 0018 movs r0, r3 + 8000df6: f7ff ff87 bl 8000d08 <cobs_decode_incremental_initialize> + return -3; + 8000dfa: 2303 movs r3, #3 + 8000dfc: 425b negs r3, r3 +} + 8000dfe: 0018 movs r0, r3 + 8000e00: 46bd mov sp, r7 + 8000e02: b008 add sp, #32 + 8000e04: bd80 pop {r7, pc} + 8000e06: 1904 .short 0x1904 + 8000e08: 00000800 .word 0x00000800 + 8000e0c: 00942000 .word 0x00942000 + 8000e10: 00942000 .word 0x00942000 + 8000e14: 09d42000 .word 0x09d42000 + 8000e18: 00002000 .word 0x00002000 + +08000e1c <SystemInit>: + * Initialize the default HSI clock source, vector table location and the PLL configuration is reset. + * @param None + * @retval None + */ +void SystemInit(void) +{ + 8000e1c: b580 push {r7, lr} + 8000e1e: af00 add r7, sp, #0 + /* Reset the RCC clock configuration to the default reset state ------------*/ + /* Set HSION bit */ + RCC->CR |= (uint32_t)0x00000001U; + 8000e20: 4b1a ldr r3, [pc, #104] ; (8000e8c <SystemInit+0x70>) + 8000e22: 681a ldr r2, [r3, #0] + 8000e24: 4b19 ldr r3, [pc, #100] ; (8000e8c <SystemInit+0x70>) + 8000e26: 2101 movs r1, #1 + 8000e28: 430a orrs r2, r1 + 8000e2a: 601a str r2, [r3, #0] +#if defined (STM32F051x8) || defined (STM32F058x8) + /* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE and MCOSEL[2:0] bits */ + RCC->CFGR &= (uint32_t)0xF8FFB80CU; +#else + /* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE, MCOSEL[2:0], MCOPRE[2:0] and PLLNODIV bits */ + RCC->CFGR &= (uint32_t)0x08FFB80CU; + 8000e2c: 4b17 ldr r3, [pc, #92] ; (8000e8c <SystemInit+0x70>) + 8000e2e: 685a ldr r2, [r3, #4] + 8000e30: 4b16 ldr r3, [pc, #88] ; (8000e8c <SystemInit+0x70>) + 8000e32: 4917 ldr r1, [pc, #92] ; (8000e90 <SystemInit+0x74>) + 8000e34: 400a ands r2, r1 + 8000e36: 605a str r2, [r3, #4] +#endif /* STM32F051x8 or STM32F058x8 */ + + /* Reset HSEON, CSSON and PLLON bits */ + RCC->CR &= (uint32_t)0xFEF6FFFFU; + 8000e38: 4b14 ldr r3, [pc, #80] ; (8000e8c <SystemInit+0x70>) + 8000e3a: 681a ldr r2, [r3, #0] + 8000e3c: 4b13 ldr r3, [pc, #76] ; (8000e8c <SystemInit+0x70>) + 8000e3e: 4915 ldr r1, [pc, #84] ; (8000e94 <SystemInit+0x78>) + 8000e40: 400a ands r2, r1 + 8000e42: 601a str r2, [r3, #0] + + /* Reset HSEBYP bit */ + RCC->CR &= (uint32_t)0xFFFBFFFFU; + 8000e44: 4b11 ldr r3, [pc, #68] ; (8000e8c <SystemInit+0x70>) + 8000e46: 681a ldr r2, [r3, #0] + 8000e48: 4b10 ldr r3, [pc, #64] ; (8000e8c <SystemInit+0x70>) + 8000e4a: 4913 ldr r1, [pc, #76] ; (8000e98 <SystemInit+0x7c>) + 8000e4c: 400a ands r2, r1 + 8000e4e: 601a str r2, [r3, #0] + + /* Reset PLLSRC, PLLXTPRE and PLLMUL[3:0] bits */ + RCC->CFGR &= (uint32_t)0xFFC0FFFFU; + 8000e50: 4b0e ldr r3, [pc, #56] ; (8000e8c <SystemInit+0x70>) + 8000e52: 685a ldr r2, [r3, #4] + 8000e54: 4b0d ldr r3, [pc, #52] ; (8000e8c <SystemInit+0x70>) + 8000e56: 4911 ldr r1, [pc, #68] ; (8000e9c <SystemInit+0x80>) + 8000e58: 400a ands r2, r1 + 8000e5a: 605a str r2, [r3, #4] + + /* Reset PREDIV[3:0] bits */ + RCC->CFGR2 &= (uint32_t)0xFFFFFFF0U; + 8000e5c: 4b0b ldr r3, [pc, #44] ; (8000e8c <SystemInit+0x70>) + 8000e5e: 6ada ldr r2, [r3, #44] ; 0x2c + 8000e60: 4b0a ldr r3, [pc, #40] ; (8000e8c <SystemInit+0x70>) + 8000e62: 210f movs r1, #15 + 8000e64: 438a bics r2, r1 + 8000e66: 62da str r2, [r3, #44] ; 0x2c +#elif defined (STM32F091xC) || defined (STM32F098xx) + /* Reset USART3SW[1:0], USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits */ + RCC->CFGR3 &= (uint32_t)0xFFF0FEACU; +#elif defined (STM32F030x6) || defined (STM32F030x8) || defined (STM32F031x6) || defined (STM32F038xx) || defined (STM32F030xC) + /* Reset USART1SW[1:0], I2C1SW and ADCSW bits */ + RCC->CFGR3 &= (uint32_t)0xFFFFFEECU; + 8000e68: 4b08 ldr r3, [pc, #32] ; (8000e8c <SystemInit+0x70>) + 8000e6a: 6b1a ldr r2, [r3, #48] ; 0x30 + 8000e6c: 4b07 ldr r3, [pc, #28] ; (8000e8c <SystemInit+0x70>) + 8000e6e: 490c ldr r1, [pc, #48] ; (8000ea0 <SystemInit+0x84>) + 8000e70: 400a ands r2, r1 + 8000e72: 631a str r2, [r3, #48] ; 0x30 +#else + #warning "No target selected" +#endif + + /* Reset HSI14 bit */ + RCC->CR2 &= (uint32_t)0xFFFFFFFEU; + 8000e74: 4b05 ldr r3, [pc, #20] ; (8000e8c <SystemInit+0x70>) + 8000e76: 6b5a ldr r2, [r3, #52] ; 0x34 + 8000e78: 4b04 ldr r3, [pc, #16] ; (8000e8c <SystemInit+0x70>) + 8000e7a: 2101 movs r1, #1 + 8000e7c: 438a bics r2, r1 + 8000e7e: 635a str r2, [r3, #52] ; 0x34 + + /* Disable all interrupts */ + RCC->CIR = 0x00000000U; + 8000e80: 4b02 ldr r3, [pc, #8] ; (8000e8c <SystemInit+0x70>) + 8000e82: 2200 movs r2, #0 + 8000e84: 609a str r2, [r3, #8] + +} + 8000e86: 46c0 nop ; (mov r8, r8) + 8000e88: 46bd mov sp, r7 + 8000e8a: bd80 pop {r7, pc} + 8000e8c: 40021000 .word 0x40021000 + 8000e90: 08ffb80c .word 0x08ffb80c + 8000e94: fef6ffff .word 0xfef6ffff + 8000e98: fffbffff .word 0xfffbffff + 8000e9c: ffc0ffff .word 0xffc0ffff + 8000ea0: fffffeec .word 0xfffffeec + +08000ea4 <SystemCoreClockUpdate>: + * + * @param None + * @retval None + */ +void SystemCoreClockUpdate (void) +{ + 8000ea4: b580 push {r7, lr} + 8000ea6: b084 sub sp, #16 + 8000ea8: af00 add r7, sp, #0 + uint32_t tmp = 0, pllmull = 0, pllsource = 0, predivfactor = 0; + 8000eaa: 2300 movs r3, #0 + 8000eac: 60fb str r3, [r7, #12] + 8000eae: 2300 movs r3, #0 + 8000eb0: 60bb str r3, [r7, #8] + 8000eb2: 2300 movs r3, #0 + 8000eb4: 607b str r3, [r7, #4] + 8000eb6: 2300 movs r3, #0 + 8000eb8: 603b str r3, [r7, #0] + + /* Get SYSCLK source -------------------------------------------------------*/ + tmp = RCC->CFGR & RCC_CFGR_SWS; + 8000eba: 4b31 ldr r3, [pc, #196] ; (8000f80 <SystemCoreClockUpdate+0xdc>) + 8000ebc: 685b ldr r3, [r3, #4] + 8000ebe: 220c movs r2, #12 + 8000ec0: 4013 ands r3, r2 + 8000ec2: 60fb str r3, [r7, #12] + + switch (tmp) + 8000ec4: 68fb ldr r3, [r7, #12] + 8000ec6: 2b08 cmp r3, #8 + 8000ec8: d011 beq.n 8000eee <SystemCoreClockUpdate+0x4a> + 8000eca: 68fb ldr r3, [r7, #12] + 8000ecc: 2b08 cmp r3, #8 + 8000ece: d841 bhi.n 8000f54 <SystemCoreClockUpdate+0xb0> + 8000ed0: 68fb ldr r3, [r7, #12] + 8000ed2: 2b00 cmp r3, #0 + 8000ed4: d003 beq.n 8000ede <SystemCoreClockUpdate+0x3a> + 8000ed6: 68fb ldr r3, [r7, #12] + 8000ed8: 2b04 cmp r3, #4 + 8000eda: d004 beq.n 8000ee6 <SystemCoreClockUpdate+0x42> + 8000edc: e03a b.n 8000f54 <SystemCoreClockUpdate+0xb0> + { + case RCC_CFGR_SWS_HSI: /* HSI used as system clock */ + SystemCoreClock = HSI_VALUE; + 8000ede: 4b29 ldr r3, [pc, #164] ; (8000f84 <SystemCoreClockUpdate+0xe0>) + 8000ee0: 4a29 ldr r2, [pc, #164] ; (8000f88 <SystemCoreClockUpdate+0xe4>) + 8000ee2: 601a str r2, [r3, #0] + break; + 8000ee4: e03a b.n 8000f5c <SystemCoreClockUpdate+0xb8> + case RCC_CFGR_SWS_HSE: /* HSE used as system clock */ + SystemCoreClock = HSE_VALUE; + 8000ee6: 4b27 ldr r3, [pc, #156] ; (8000f84 <SystemCoreClockUpdate+0xe0>) + 8000ee8: 4a27 ldr r2, [pc, #156] ; (8000f88 <SystemCoreClockUpdate+0xe4>) + 8000eea: 601a str r2, [r3, #0] + break; + 8000eec: e036 b.n 8000f5c <SystemCoreClockUpdate+0xb8> + case RCC_CFGR_SWS_PLL: /* PLL used as system clock */ + /* Get PLL clock source and multiplication factor ----------------------*/ + pllmull = RCC->CFGR & RCC_CFGR_PLLMUL; + 8000eee: 4b24 ldr r3, [pc, #144] ; (8000f80 <SystemCoreClockUpdate+0xdc>) + 8000ef0: 685a ldr r2, [r3, #4] + 8000ef2: 23f0 movs r3, #240 ; 0xf0 + 8000ef4: 039b lsls r3, r3, #14 + 8000ef6: 4013 ands r3, r2 + 8000ef8: 60bb str r3, [r7, #8] + pllsource = RCC->CFGR & RCC_CFGR_PLLSRC; + 8000efa: 4b21 ldr r3, [pc, #132] ; (8000f80 <SystemCoreClockUpdate+0xdc>) + 8000efc: 685a ldr r2, [r3, #4] + 8000efe: 2380 movs r3, #128 ; 0x80 + 8000f00: 025b lsls r3, r3, #9 + 8000f02: 4013 ands r3, r2 + 8000f04: 607b str r3, [r7, #4] + pllmull = ( pllmull >> 18) + 2; + 8000f06: 68bb ldr r3, [r7, #8] + 8000f08: 0c9b lsrs r3, r3, #18 + 8000f0a: 3302 adds r3, #2 + 8000f0c: 60bb str r3, [r7, #8] + predivfactor = (RCC->CFGR2 & RCC_CFGR2_PREDIV) + 1; + 8000f0e: 4b1c ldr r3, [pc, #112] ; (8000f80 <SystemCoreClockUpdate+0xdc>) + 8000f10: 6adb ldr r3, [r3, #44] ; 0x2c + 8000f12: 220f movs r2, #15 + 8000f14: 4013 ands r3, r2 + 8000f16: 3301 adds r3, #1 + 8000f18: 603b str r3, [r7, #0] + + if (pllsource == RCC_CFGR_PLLSRC_HSE_PREDIV) + 8000f1a: 687a ldr r2, [r7, #4] + 8000f1c: 2380 movs r3, #128 ; 0x80 + 8000f1e: 025b lsls r3, r3, #9 + 8000f20: 429a cmp r2, r3 + 8000f22: d10a bne.n 8000f3a <SystemCoreClockUpdate+0x96> + { + /* HSE used as PLL clock source : SystemCoreClock = HSE/PREDIV * PLLMUL */ + SystemCoreClock = (HSE_VALUE/predivfactor) * pllmull; + 8000f24: 6839 ldr r1, [r7, #0] + 8000f26: 4818 ldr r0, [pc, #96] ; (8000f88 <SystemCoreClockUpdate+0xe4>) + 8000f28: f000 fb3e bl 80015a8 <__udivsi3> + 8000f2c: 0003 movs r3, r0 + 8000f2e: 001a movs r2, r3 + 8000f30: 68bb ldr r3, [r7, #8] + 8000f32: 435a muls r2, r3 + 8000f34: 4b13 ldr r3, [pc, #76] ; (8000f84 <SystemCoreClockUpdate+0xe0>) + 8000f36: 601a str r2, [r3, #0] + SystemCoreClock = (HSI_VALUE >> 1) * pllmull; +#endif /* STM32F042x6 || STM32F048xx || STM32F070x6 || + STM32F071xB || STM32F072xB || STM32F078xx || STM32F070xB || + STM32F091xC || STM32F098xx || STM32F030xC */ + } + break; + 8000f38: e010 b.n 8000f5c <SystemCoreClockUpdate+0xb8> + SystemCoreClock = (HSI_VALUE >> 1) * pllmull; + 8000f3a: 68b9 ldr r1, [r7, #8] + 8000f3c: 000a movs r2, r1 + 8000f3e: 0152 lsls r2, r2, #5 + 8000f40: 1a52 subs r2, r2, r1 + 8000f42: 0193 lsls r3, r2, #6 + 8000f44: 1a9b subs r3, r3, r2 + 8000f46: 00db lsls r3, r3, #3 + 8000f48: 185b adds r3, r3, r1 + 8000f4a: 021b lsls r3, r3, #8 + 8000f4c: 001a movs r2, r3 + 8000f4e: 4b0d ldr r3, [pc, #52] ; (8000f84 <SystemCoreClockUpdate+0xe0>) + 8000f50: 601a str r2, [r3, #0] + break; + 8000f52: e003 b.n 8000f5c <SystemCoreClockUpdate+0xb8> + default: /* HSI used as system clock */ + SystemCoreClock = HSI_VALUE; + 8000f54: 4b0b ldr r3, [pc, #44] ; (8000f84 <SystemCoreClockUpdate+0xe0>) + 8000f56: 4a0c ldr r2, [pc, #48] ; (8000f88 <SystemCoreClockUpdate+0xe4>) + 8000f58: 601a str r2, [r3, #0] + break; + 8000f5a: 46c0 nop ; (mov r8, r8) + } + /* Compute HCLK clock frequency ----------------*/ + /* Get HCLK prescaler */ + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; + 8000f5c: 4b08 ldr r3, [pc, #32] ; (8000f80 <SystemCoreClockUpdate+0xdc>) + 8000f5e: 685b ldr r3, [r3, #4] + 8000f60: 091b lsrs r3, r3, #4 + 8000f62: 220f movs r2, #15 + 8000f64: 4013 ands r3, r2 + 8000f66: 4a09 ldr r2, [pc, #36] ; (8000f8c <SystemCoreClockUpdate+0xe8>) + 8000f68: 5cd3 ldrb r3, [r2, r3] + 8000f6a: 60fb str r3, [r7, #12] + /* HCLK clock frequency */ + SystemCoreClock >>= tmp; + 8000f6c: 4b05 ldr r3, [pc, #20] ; (8000f84 <SystemCoreClockUpdate+0xe0>) + 8000f6e: 681a ldr r2, [r3, #0] + 8000f70: 68fb ldr r3, [r7, #12] + 8000f72: 40da lsrs r2, r3 + 8000f74: 4b03 ldr r3, [pc, #12] ; (8000f84 <SystemCoreClockUpdate+0xe0>) + 8000f76: 601a str r2, [r3, #0] +} + 8000f78: 46c0 nop ; (mov r8, r8) + 8000f7a: 46bd mov sp, r7 + 8000f7c: b004 add sp, #16 + 8000f7e: bd80 pop {r7, pc} + 8000f80: 40021000 .word 0x40021000 + 8000f84: 20000000 .word 0x20000000 + 8000f88: 007a1200 .word 0x007a1200 + 8000f8c: 080018ec .word 0x080018ec + +08000f90 <LL_RCC_HSE_EnableBypass>: + * @brief Enable HSE external oscillator (HSE Bypass) + * @rmtoll CR HSEBYP LL_RCC_HSE_EnableBypass + * @retval None + */ +__STATIC_INLINE void LL_RCC_HSE_EnableBypass(void) +{ + 8000f90: b580 push {r7, lr} + 8000f92: af00 add r7, sp, #0 + SET_BIT(RCC->CR, RCC_CR_HSEBYP); + 8000f94: 4b04 ldr r3, [pc, #16] ; (8000fa8 <LL_RCC_HSE_EnableBypass+0x18>) + 8000f96: 681a ldr r2, [r3, #0] + 8000f98: 4b03 ldr r3, [pc, #12] ; (8000fa8 <LL_RCC_HSE_EnableBypass+0x18>) + 8000f9a: 2180 movs r1, #128 ; 0x80 + 8000f9c: 02c9 lsls r1, r1, #11 + 8000f9e: 430a orrs r2, r1 + 8000fa0: 601a str r2, [r3, #0] +} + 8000fa2: 46c0 nop ; (mov r8, r8) + 8000fa4: 46bd mov sp, r7 + 8000fa6: bd80 pop {r7, pc} + 8000fa8: 40021000 .word 0x40021000 + +08000fac <LL_RCC_HSE_DisableBypass>: + * @brief Disable HSE external oscillator (HSE Bypass) + * @rmtoll CR HSEBYP LL_RCC_HSE_DisableBypass + * @retval None + */ +__STATIC_INLINE void LL_RCC_HSE_DisableBypass(void) +{ + 8000fac: b580 push {r7, lr} + 8000fae: af00 add r7, sp, #0 + CLEAR_BIT(RCC->CR, RCC_CR_HSEBYP); + 8000fb0: 4b04 ldr r3, [pc, #16] ; (8000fc4 <LL_RCC_HSE_DisableBypass+0x18>) + 8000fb2: 681a ldr r2, [r3, #0] + 8000fb4: 4b03 ldr r3, [pc, #12] ; (8000fc4 <LL_RCC_HSE_DisableBypass+0x18>) + 8000fb6: 4904 ldr r1, [pc, #16] ; (8000fc8 <LL_RCC_HSE_DisableBypass+0x1c>) + 8000fb8: 400a ands r2, r1 + 8000fba: 601a str r2, [r3, #0] +} + 8000fbc: 46c0 nop ; (mov r8, r8) + 8000fbe: 46bd mov sp, r7 + 8000fc0: bd80 pop {r7, pc} + 8000fc2: 46c0 nop ; (mov r8, r8) + 8000fc4: 40021000 .word 0x40021000 + 8000fc8: fffbffff .word 0xfffbffff + +08000fcc <LL_RCC_HSE_Enable>: + * @brief Enable HSE crystal oscillator (HSE ON) + * @rmtoll CR HSEON LL_RCC_HSE_Enable + * @retval None + */ +__STATIC_INLINE void LL_RCC_HSE_Enable(void) +{ + 8000fcc: b580 push {r7, lr} + 8000fce: af00 add r7, sp, #0 + SET_BIT(RCC->CR, RCC_CR_HSEON); + 8000fd0: 4b04 ldr r3, [pc, #16] ; (8000fe4 <LL_RCC_HSE_Enable+0x18>) + 8000fd2: 681a ldr r2, [r3, #0] + 8000fd4: 4b03 ldr r3, [pc, #12] ; (8000fe4 <LL_RCC_HSE_Enable+0x18>) + 8000fd6: 2180 movs r1, #128 ; 0x80 + 8000fd8: 0249 lsls r1, r1, #9 + 8000fda: 430a orrs r2, r1 + 8000fdc: 601a str r2, [r3, #0] +} + 8000fde: 46c0 nop ; (mov r8, r8) + 8000fe0: 46bd mov sp, r7 + 8000fe2: bd80 pop {r7, pc} + 8000fe4: 40021000 .word 0x40021000 + +08000fe8 <LL_RCC_HSE_IsReady>: + * @brief Check if HSE oscillator Ready + * @rmtoll CR HSERDY LL_RCC_HSE_IsReady + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_RCC_HSE_IsReady(void) +{ + 8000fe8: b580 push {r7, lr} + 8000fea: af00 add r7, sp, #0 + return (READ_BIT(RCC->CR, RCC_CR_HSERDY) == (RCC_CR_HSERDY)); + 8000fec: 4b06 ldr r3, [pc, #24] ; (8001008 <LL_RCC_HSE_IsReady+0x20>) + 8000fee: 681a ldr r2, [r3, #0] + 8000ff0: 2380 movs r3, #128 ; 0x80 + 8000ff2: 029b lsls r3, r3, #10 + 8000ff4: 4013 ands r3, r2 + 8000ff6: 4a05 ldr r2, [pc, #20] ; (800100c <LL_RCC_HSE_IsReady+0x24>) + 8000ff8: 4694 mov ip, r2 + 8000ffa: 4463 add r3, ip + 8000ffc: 425a negs r2, r3 + 8000ffe: 4153 adcs r3, r2 + 8001000: b2db uxtb r3, r3 +} + 8001002: 0018 movs r0, r3 + 8001004: 46bd mov sp, r7 + 8001006: bd80 pop {r7, pc} + 8001008: 40021000 .word 0x40021000 + 800100c: fffe0000 .word 0xfffe0000 + +08001010 <LL_RCC_HSI_Enable>: + * @brief Enable HSI oscillator + * @rmtoll CR HSION LL_RCC_HSI_Enable + * @retval None + */ +__STATIC_INLINE void LL_RCC_HSI_Enable(void) +{ + 8001010: b580 push {r7, lr} + 8001012: af00 add r7, sp, #0 + SET_BIT(RCC->CR, RCC_CR_HSION); + 8001014: 4b04 ldr r3, [pc, #16] ; (8001028 <LL_RCC_HSI_Enable+0x18>) + 8001016: 681a ldr r2, [r3, #0] + 8001018: 4b03 ldr r3, [pc, #12] ; (8001028 <LL_RCC_HSI_Enable+0x18>) + 800101a: 2101 movs r1, #1 + 800101c: 430a orrs r2, r1 + 800101e: 601a str r2, [r3, #0] +} + 8001020: 46c0 nop ; (mov r8, r8) + 8001022: 46bd mov sp, r7 + 8001024: bd80 pop {r7, pc} + 8001026: 46c0 nop ; (mov r8, r8) + 8001028: 40021000 .word 0x40021000 + +0800102c <LL_RCC_HSI_IsReady>: + * @brief Check if HSI clock is ready + * @rmtoll CR HSIRDY LL_RCC_HSI_IsReady + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_RCC_HSI_IsReady(void) +{ + 800102c: b580 push {r7, lr} + 800102e: af00 add r7, sp, #0 + return (READ_BIT(RCC->CR, RCC_CR_HSIRDY) == (RCC_CR_HSIRDY)); + 8001030: 4b05 ldr r3, [pc, #20] ; (8001048 <LL_RCC_HSI_IsReady+0x1c>) + 8001032: 681b ldr r3, [r3, #0] + 8001034: 2202 movs r2, #2 + 8001036: 4013 ands r3, r2 + 8001038: 3b02 subs r3, #2 + 800103a: 425a negs r2, r3 + 800103c: 4153 adcs r3, r2 + 800103e: b2db uxtb r3, r3 +} + 8001040: 0018 movs r0, r3 + 8001042: 46bd mov sp, r7 + 8001044: bd80 pop {r7, pc} + 8001046: 46c0 nop ; (mov r8, r8) + 8001048: 40021000 .word 0x40021000 + +0800104c <LL_RCC_SetSysClkSource>: + * + * (*) value not defined in all devices + * @retval None + */ +__STATIC_INLINE void LL_RCC_SetSysClkSource(uint32_t Source) +{ + 800104c: b580 push {r7, lr} + 800104e: b082 sub sp, #8 + 8001050: af00 add r7, sp, #0 + 8001052: 6078 str r0, [r7, #4] + MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, Source); + 8001054: 4b06 ldr r3, [pc, #24] ; (8001070 <LL_RCC_SetSysClkSource+0x24>) + 8001056: 685b ldr r3, [r3, #4] + 8001058: 2203 movs r2, #3 + 800105a: 4393 bics r3, r2 + 800105c: 0019 movs r1, r3 + 800105e: 4b04 ldr r3, [pc, #16] ; (8001070 <LL_RCC_SetSysClkSource+0x24>) + 8001060: 687a ldr r2, [r7, #4] + 8001062: 430a orrs r2, r1 + 8001064: 605a str r2, [r3, #4] +} + 8001066: 46c0 nop ; (mov r8, r8) + 8001068: 46bd mov sp, r7 + 800106a: b002 add sp, #8 + 800106c: bd80 pop {r7, pc} + 800106e: 46c0 nop ; (mov r8, r8) + 8001070: 40021000 .word 0x40021000 + +08001074 <LL_RCC_GetSysClkSource>: + * @arg @ref LL_RCC_SYS_CLKSOURCE_STATUS_HSI48 (*) + * + * (*) value not defined in all devices + */ +__STATIC_INLINE uint32_t LL_RCC_GetSysClkSource(void) +{ + 8001074: b580 push {r7, lr} + 8001076: af00 add r7, sp, #0 + return (uint32_t)(READ_BIT(RCC->CFGR, RCC_CFGR_SWS)); + 8001078: 4b03 ldr r3, [pc, #12] ; (8001088 <LL_RCC_GetSysClkSource+0x14>) + 800107a: 685b ldr r3, [r3, #4] + 800107c: 220c movs r2, #12 + 800107e: 4013 ands r3, r2 +} + 8001080: 0018 movs r0, r3 + 8001082: 46bd mov sp, r7 + 8001084: bd80 pop {r7, pc} + 8001086: 46c0 nop ; (mov r8, r8) + 8001088: 40021000 .word 0x40021000 + +0800108c <LL_RCC_SetAHBPrescaler>: + * @arg @ref LL_RCC_SYSCLK_DIV_256 + * @arg @ref LL_RCC_SYSCLK_DIV_512 + * @retval None + */ +__STATIC_INLINE void LL_RCC_SetAHBPrescaler(uint32_t Prescaler) +{ + 800108c: b580 push {r7, lr} + 800108e: b082 sub sp, #8 + 8001090: af00 add r7, sp, #0 + 8001092: 6078 str r0, [r7, #4] + MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, Prescaler); + 8001094: 4b06 ldr r3, [pc, #24] ; (80010b0 <LL_RCC_SetAHBPrescaler+0x24>) + 8001096: 685b ldr r3, [r3, #4] + 8001098: 22f0 movs r2, #240 ; 0xf0 + 800109a: 4393 bics r3, r2 + 800109c: 0019 movs r1, r3 + 800109e: 4b04 ldr r3, [pc, #16] ; (80010b0 <LL_RCC_SetAHBPrescaler+0x24>) + 80010a0: 687a ldr r2, [r7, #4] + 80010a2: 430a orrs r2, r1 + 80010a4: 605a str r2, [r3, #4] +} + 80010a6: 46c0 nop ; (mov r8, r8) + 80010a8: 46bd mov sp, r7 + 80010aa: b002 add sp, #8 + 80010ac: bd80 pop {r7, pc} + 80010ae: 46c0 nop ; (mov r8, r8) + 80010b0: 40021000 .word 0x40021000 + +080010b4 <LL_RCC_SetAPB1Prescaler>: + * @arg @ref LL_RCC_APB1_DIV_8 + * @arg @ref LL_RCC_APB1_DIV_16 + * @retval None + */ +__STATIC_INLINE void LL_RCC_SetAPB1Prescaler(uint32_t Prescaler) +{ + 80010b4: b580 push {r7, lr} + 80010b6: b082 sub sp, #8 + 80010b8: af00 add r7, sp, #0 + 80010ba: 6078 str r0, [r7, #4] + MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE, Prescaler); + 80010bc: 4b06 ldr r3, [pc, #24] ; (80010d8 <LL_RCC_SetAPB1Prescaler+0x24>) + 80010be: 685b ldr r3, [r3, #4] + 80010c0: 4a06 ldr r2, [pc, #24] ; (80010dc <LL_RCC_SetAPB1Prescaler+0x28>) + 80010c2: 4013 ands r3, r2 + 80010c4: 0019 movs r1, r3 + 80010c6: 4b04 ldr r3, [pc, #16] ; (80010d8 <LL_RCC_SetAPB1Prescaler+0x24>) + 80010c8: 687a ldr r2, [r7, #4] + 80010ca: 430a orrs r2, r1 + 80010cc: 605a str r2, [r3, #4] +} + 80010ce: 46c0 nop ; (mov r8, r8) + 80010d0: 46bd mov sp, r7 + 80010d2: b002 add sp, #8 + 80010d4: bd80 pop {r7, pc} + 80010d6: 46c0 nop ; (mov r8, r8) + 80010d8: 40021000 .word 0x40021000 + 80010dc: fffff8ff .word 0xfffff8ff + +080010e0 <LL_RCC_PLL_Enable>: + * @brief Enable PLL + * @rmtoll CR PLLON LL_RCC_PLL_Enable + * @retval None + */ +__STATIC_INLINE void LL_RCC_PLL_Enable(void) +{ + 80010e0: b580 push {r7, lr} + 80010e2: af00 add r7, sp, #0 + SET_BIT(RCC->CR, RCC_CR_PLLON); + 80010e4: 4b04 ldr r3, [pc, #16] ; (80010f8 <LL_RCC_PLL_Enable+0x18>) + 80010e6: 681a ldr r2, [r3, #0] + 80010e8: 4b03 ldr r3, [pc, #12] ; (80010f8 <LL_RCC_PLL_Enable+0x18>) + 80010ea: 2180 movs r1, #128 ; 0x80 + 80010ec: 0449 lsls r1, r1, #17 + 80010ee: 430a orrs r2, r1 + 80010f0: 601a str r2, [r3, #0] +} + 80010f2: 46c0 nop ; (mov r8, r8) + 80010f4: 46bd mov sp, r7 + 80010f6: bd80 pop {r7, pc} + 80010f8: 40021000 .word 0x40021000 + +080010fc <LL_RCC_PLL_IsReady>: + * @brief Check if PLL Ready + * @rmtoll CR PLLRDY LL_RCC_PLL_IsReady + * @retval State of bit (1 or 0). + */ +__STATIC_INLINE uint32_t LL_RCC_PLL_IsReady(void) +{ + 80010fc: b580 push {r7, lr} + 80010fe: af00 add r7, sp, #0 + return (READ_BIT(RCC->CR, RCC_CR_PLLRDY) == (RCC_CR_PLLRDY)); + 8001100: 4b07 ldr r3, [pc, #28] ; (8001120 <LL_RCC_PLL_IsReady+0x24>) + 8001102: 681a ldr r2, [r3, #0] + 8001104: 2380 movs r3, #128 ; 0x80 + 8001106: 049b lsls r3, r3, #18 + 8001108: 4013 ands r3, r2 + 800110a: 22fe movs r2, #254 ; 0xfe + 800110c: 0612 lsls r2, r2, #24 + 800110e: 4694 mov ip, r2 + 8001110: 4463 add r3, ip + 8001112: 425a negs r2, r3 + 8001114: 4153 adcs r3, r2 + 8001116: b2db uxtb r3, r3 +} + 8001118: 0018 movs r0, r3 + 800111a: 46bd mov sp, r7 + 800111c: bd80 pop {r7, pc} + 800111e: 46c0 nop ; (mov r8, r8) + 8001120: 40021000 .word 0x40021000 + +08001124 <LL_RCC_PLL_ConfigDomain_SYS>: + * @arg @ref LL_RCC_PLL_MUL_15 + * @arg @ref LL_RCC_PLL_MUL_16 + * @retval None + */ +__STATIC_INLINE void LL_RCC_PLL_ConfigDomain_SYS(uint32_t Source, uint32_t PLLMul) +{ + 8001124: b580 push {r7, lr} + 8001126: b082 sub sp, #8 + 8001128: af00 add r7, sp, #0 + 800112a: 6078 str r0, [r7, #4] + 800112c: 6039 str r1, [r7, #0] + MODIFY_REG(RCC->CFGR, RCC_CFGR_PLLSRC | RCC_CFGR_PLLMUL, (Source & RCC_CFGR_PLLSRC) | PLLMul); + 800112e: 4b0e ldr r3, [pc, #56] ; (8001168 <LL_RCC_PLL_ConfigDomain_SYS+0x44>) + 8001130: 685b ldr r3, [r3, #4] + 8001132: 4a0e ldr r2, [pc, #56] ; (800116c <LL_RCC_PLL_ConfigDomain_SYS+0x48>) + 8001134: 4013 ands r3, r2 + 8001136: 0019 movs r1, r3 + 8001138: 687a ldr r2, [r7, #4] + 800113a: 2380 movs r3, #128 ; 0x80 + 800113c: 025b lsls r3, r3, #9 + 800113e: 401a ands r2, r3 + 8001140: 683b ldr r3, [r7, #0] + 8001142: 431a orrs r2, r3 + 8001144: 4b08 ldr r3, [pc, #32] ; (8001168 <LL_RCC_PLL_ConfigDomain_SYS+0x44>) + 8001146: 430a orrs r2, r1 + 8001148: 605a str r2, [r3, #4] + MODIFY_REG(RCC->CFGR2, RCC_CFGR2_PREDIV, (Source & RCC_CFGR2_PREDIV)); + 800114a: 4b07 ldr r3, [pc, #28] ; (8001168 <LL_RCC_PLL_ConfigDomain_SYS+0x44>) + 800114c: 6adb ldr r3, [r3, #44] ; 0x2c + 800114e: 220f movs r2, #15 + 8001150: 4393 bics r3, r2 + 8001152: 0019 movs r1, r3 + 8001154: 687b ldr r3, [r7, #4] + 8001156: 220f movs r2, #15 + 8001158: 401a ands r2, r3 + 800115a: 4b03 ldr r3, [pc, #12] ; (8001168 <LL_RCC_PLL_ConfigDomain_SYS+0x44>) + 800115c: 430a orrs r2, r1 + 800115e: 62da str r2, [r3, #44] ; 0x2c +} + 8001160: 46c0 nop ; (mov r8, r8) + 8001162: 46bd mov sp, r7 + 8001164: b002 add sp, #8 + 8001166: bd80 pop {r7, pc} + 8001168: 40021000 .word 0x40021000 + 800116c: ffc2ffff .word 0xffc2ffff + +08001170 <LL_InitTick>: + * configuration by calling this function, for a delay use rather osDelay RTOS service. + * @param Ticks Number of ticks + * @retval None + */ +__STATIC_INLINE void LL_InitTick(uint32_t HCLKFrequency, uint32_t Ticks) +{ + 8001170: b580 push {r7, lr} + 8001172: b082 sub sp, #8 + 8001174: af00 add r7, sp, #0 + 8001176: 6078 str r0, [r7, #4] + 8001178: 6039 str r1, [r7, #0] + /* Configure the SysTick to have interrupt in 1ms time base */ + SysTick->LOAD = (uint32_t)((HCLKFrequency / Ticks) - 1UL); /* set reload register */ + 800117a: 6839 ldr r1, [r7, #0] + 800117c: 6878 ldr r0, [r7, #4] + 800117e: f000 fa13 bl 80015a8 <__udivsi3> + 8001182: 0003 movs r3, r0 + 8001184: 001a movs r2, r3 + 8001186: 4b06 ldr r3, [pc, #24] ; (80011a0 <LL_InitTick+0x30>) + 8001188: 3a01 subs r2, #1 + 800118a: 605a str r2, [r3, #4] + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + 800118c: 4b04 ldr r3, [pc, #16] ; (80011a0 <LL_InitTick+0x30>) + 800118e: 2200 movs r2, #0 + 8001190: 609a str r2, [r3, #8] + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + 8001192: 4b03 ldr r3, [pc, #12] ; (80011a0 <LL_InitTick+0x30>) + 8001194: 2205 movs r2, #5 + 8001196: 601a str r2, [r3, #0] + SysTick_CTRL_ENABLE_Msk; /* Enable the Systick Timer */ +} + 8001198: 46c0 nop ; (mov r8, r8) + 800119a: 46bd mov sp, r7 + 800119c: b002 add sp, #8 + 800119e: bd80 pop {r7, pc} + 80011a0: e000e010 .word 0xe000e010 + +080011a4 <LL_FLASH_SetLatency>: + * @arg @ref LL_FLASH_LATENCY_0 + * @arg @ref LL_FLASH_LATENCY_1 + * @retval None + */ +__STATIC_INLINE void LL_FLASH_SetLatency(uint32_t Latency) +{ + 80011a4: b580 push {r7, lr} + 80011a6: b082 sub sp, #8 + 80011a8: af00 add r7, sp, #0 + 80011aa: 6078 str r0, [r7, #4] + MODIFY_REG(FLASH->ACR, FLASH_ACR_LATENCY, Latency); + 80011ac: 4b06 ldr r3, [pc, #24] ; (80011c8 <LL_FLASH_SetLatency+0x24>) + 80011ae: 681b ldr r3, [r3, #0] + 80011b0: 2201 movs r2, #1 + 80011b2: 4393 bics r3, r2 + 80011b4: 0019 movs r1, r3 + 80011b6: 4b04 ldr r3, [pc, #16] ; (80011c8 <LL_FLASH_SetLatency+0x24>) + 80011b8: 687a ldr r2, [r7, #4] + 80011ba: 430a orrs r2, r1 + 80011bc: 601a str r2, [r3, #0] +} + 80011be: 46c0 nop ; (mov r8, r8) + 80011c0: 46bd mov sp, r7 + 80011c2: b002 add sp, #8 + 80011c4: bd80 pop {r7, pc} + 80011c6: 46c0 nop ; (mov r8, r8) + 80011c8: 40022000 .word 0x40022000 + +080011cc <LL_FLASH_GetLatency>: + * @retval Returned value can be one of the following values: + * @arg @ref LL_FLASH_LATENCY_0 + * @arg @ref LL_FLASH_LATENCY_1 + */ +__STATIC_INLINE uint32_t LL_FLASH_GetLatency(void) +{ + 80011cc: b580 push {r7, lr} + 80011ce: af00 add r7, sp, #0 + return (uint32_t)(READ_BIT(FLASH->ACR, FLASH_ACR_LATENCY)); + 80011d0: 4b03 ldr r3, [pc, #12] ; (80011e0 <LL_FLASH_GetLatency+0x14>) + 80011d2: 681b ldr r3, [r3, #0] + 80011d4: 2201 movs r2, #1 + 80011d6: 4013 ands r3, r2 +} + 80011d8: 0018 movs r0, r3 + 80011da: 46bd mov sp, r7 + 80011dc: bd80 pop {r7, pc} + 80011de: 46c0 nop ; (mov r8, r8) + 80011e0: 40022000 .word 0x40022000 + +080011e4 <LL_Init1msTick>: + * @param HCLKFrequency HCLK frequency in Hz + * @note HCLK frequency can be calculated thanks to RCC helper macro or function @ref LL_RCC_GetSystemClocksFreq + * @retval None + */ +void LL_Init1msTick(uint32_t HCLKFrequency) +{ + 80011e4: b580 push {r7, lr} + 80011e6: b082 sub sp, #8 + 80011e8: af00 add r7, sp, #0 + 80011ea: 6078 str r0, [r7, #4] + /* Use frequency provided in argument */ + LL_InitTick(HCLKFrequency, 1000U); + 80011ec: 23fa movs r3, #250 ; 0xfa + 80011ee: 009a lsls r2, r3, #2 + 80011f0: 687b ldr r3, [r7, #4] + 80011f2: 0011 movs r1, r2 + 80011f4: 0018 movs r0, r3 + 80011f6: f7ff ffbb bl 8001170 <LL_InitTick> +} + 80011fa: 46c0 nop ; (mov r8, r8) + 80011fc: 46bd mov sp, r7 + 80011fe: b002 add sp, #8 + 8001200: bd80 pop {r7, pc} + +08001202 <LL_mDelay>: + * will configure Systick to 1ms + * @param Delay specifies the delay time length, in milliseconds. + * @retval None + */ +void LL_mDelay(uint32_t Delay) +{ + 8001202: b580 push {r7, lr} + 8001204: b084 sub sp, #16 + 8001206: af00 add r7, sp, #0 + 8001208: 6078 str r0, [r7, #4] + __IO uint32_t tmp = SysTick->CTRL; /* Clear the COUNTFLAG first */ + 800120a: 4b0e ldr r3, [pc, #56] ; (8001244 <LL_mDelay+0x42>) + 800120c: 681b ldr r3, [r3, #0] + 800120e: 60fb str r3, [r7, #12] + /* Add this code to indicate that local variable is not used */ + ((void)tmp); + 8001210: 68fb ldr r3, [r7, #12] + + /* Add a period to guaranty minimum wait */ + if (Delay < LL_MAX_DELAY) + 8001212: 687b ldr r3, [r7, #4] + 8001214: 3301 adds r3, #1 + 8001216: d00c beq.n 8001232 <LL_mDelay+0x30> + { + Delay++; + 8001218: 687b ldr r3, [r7, #4] + 800121a: 3301 adds r3, #1 + 800121c: 607b str r3, [r7, #4] + } + + while (Delay) + 800121e: e008 b.n 8001232 <LL_mDelay+0x30> + { + if ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG_Msk) != 0U) + 8001220: 4b08 ldr r3, [pc, #32] ; (8001244 <LL_mDelay+0x42>) + 8001222: 681a ldr r2, [r3, #0] + 8001224: 2380 movs r3, #128 ; 0x80 + 8001226: 025b lsls r3, r3, #9 + 8001228: 4013 ands r3, r2 + 800122a: d002 beq.n 8001232 <LL_mDelay+0x30> + { + Delay--; + 800122c: 687b ldr r3, [r7, #4] + 800122e: 3b01 subs r3, #1 + 8001230: 607b str r3, [r7, #4] + while (Delay) + 8001232: 687b ldr r3, [r7, #4] + 8001234: 2b00 cmp r3, #0 + 8001236: d1f3 bne.n 8001220 <LL_mDelay+0x1e> + } + } +} + 8001238: 46c0 nop ; (mov r8, r8) + 800123a: 46c0 nop ; (mov r8, r8) + 800123c: 46bd mov sp, r7 + 800123e: b004 add sp, #16 + 8001240: bd80 pop {r7, pc} + 8001242: 46c0 nop ; (mov r8, r8) + 8001244: e000e010 .word 0xe000e010 + +08001248 <LL_SetSystemCoreClock>: + * @note Variable can be calculated also through SystemCoreClockUpdate function. + * @param HCLKFrequency HCLK frequency in Hz (can be calculated thanks to RCC helper macro) + * @retval None + */ +void LL_SetSystemCoreClock(uint32_t HCLKFrequency) +{ + 8001248: b580 push {r7, lr} + 800124a: b082 sub sp, #8 + 800124c: af00 add r7, sp, #0 + 800124e: 6078 str r0, [r7, #4] + /* HCLK clock frequency */ + SystemCoreClock = HCLKFrequency; + 8001250: 4b03 ldr r3, [pc, #12] ; (8001260 <LL_SetSystemCoreClock+0x18>) + 8001252: 687a ldr r2, [r7, #4] + 8001254: 601a str r2, [r3, #0] +} + 8001256: 46c0 nop ; (mov r8, r8) + 8001258: 46bd mov sp, r7 + 800125a: b002 add sp, #8 + 800125c: bd80 pop {r7, pc} + 800125e: 46c0 nop ; (mov r8, r8) + 8001260: 20000000 .word 0x20000000 + +08001264 <LL_PLL_ConfigSystemClock_HSI>: + * - SUCCESS: Max frequency configuration done + * - ERROR: Max frequency configuration not done + */ +ErrorStatus LL_PLL_ConfigSystemClock_HSI(LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct, + LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct) +{ + 8001264: b590 push {r4, r7, lr} + 8001266: b085 sub sp, #20 + 8001268: af00 add r7, sp, #0 + 800126a: 6078 str r0, [r7, #4] + 800126c: 6039 str r1, [r7, #0] + ErrorStatus status = SUCCESS; + 800126e: 230f movs r3, #15 + 8001270: 18fb adds r3, r7, r3 + 8001272: 2201 movs r2, #1 + 8001274: 701a strb r2, [r3, #0] + uint32_t pllfreq = 0U; + 8001276: 2300 movs r3, #0 + 8001278: 60bb str r3, [r7, #8] + + /* Check if one of the PLL is enabled */ + if (UTILS_PLL_IsBusy() == SUCCESS) + 800127a: f000 f8d4 bl 8001426 <UTILS_PLL_IsBusy> + 800127e: 0003 movs r3, r0 + 8001280: 2b01 cmp r3, #1 + 8001282: d128 bne.n 80012d6 <LL_PLL_ConfigSystemClock_HSI+0x72> +#if defined(RCC_PLLSRC_PREDIV1_SUPPORT) + /* Check PREDIV value */ + assert_param(IS_LL_UTILS_PREDIV_VALUE(UTILS_PLLInitStruct->PLLDiv)); +#else + /* Force PREDIV value to 2 */ + UTILS_PLLInitStruct->Prediv = LL_RCC_PREDIV_DIV_2; + 8001284: 687b ldr r3, [r7, #4] + 8001286: 2201 movs r2, #1 + 8001288: 605a str r2, [r3, #4] +#endif /*RCC_PLLSRC_PREDIV1_SUPPORT*/ + + /* Calculate the new PLL output frequency */ + pllfreq = UTILS_GetPLLOutputFrequency(HSI_VALUE, UTILS_PLLInitStruct); + 800128a: 687b ldr r3, [r7, #4] + 800128c: 4a17 ldr r2, [pc, #92] ; (80012ec <LL_PLL_ConfigSystemClock_HSI+0x88>) + 800128e: 0019 movs r1, r3 + 8001290: 0010 movs r0, r2 + 8001292: f000 f8ab bl 80013ec <UTILS_GetPLLOutputFrequency> + 8001296: 0003 movs r3, r0 + 8001298: 60bb str r3, [r7, #8] + + /* Enable HSI if not enabled */ + if (LL_RCC_HSI_IsReady() != 1U) + 800129a: f7ff fec7 bl 800102c <LL_RCC_HSI_IsReady> + 800129e: 0003 movs r3, r0 + 80012a0: 2b01 cmp r3, #1 + 80012a2: d007 beq.n 80012b4 <LL_PLL_ConfigSystemClock_HSI+0x50> + { + LL_RCC_HSI_Enable(); + 80012a4: f7ff feb4 bl 8001010 <LL_RCC_HSI_Enable> + while (LL_RCC_HSI_IsReady() != 1U) + 80012a8: 46c0 nop ; (mov r8, r8) + 80012aa: f7ff febf bl 800102c <LL_RCC_HSI_IsReady> + 80012ae: 0003 movs r3, r0 + 80012b0: 2b01 cmp r3, #1 + 80012b2: d1fa bne.n 80012aa <LL_PLL_ConfigSystemClock_HSI+0x46> + + /* Configure PLL */ +#if defined(RCC_PLLSRC_PREDIV1_SUPPORT) + LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI, UTILS_PLLInitStruct->PLLMul, UTILS_PLLInitStruct->PLLDiv); +#else + LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSI_DIV_2, UTILS_PLLInitStruct->PLLMul); + 80012b4: 687b ldr r3, [r7, #4] + 80012b6: 681b ldr r3, [r3, #0] + 80012b8: 0019 movs r1, r3 + 80012ba: 2000 movs r0, #0 + 80012bc: f7ff ff32 bl 8001124 <LL_RCC_PLL_ConfigDomain_SYS> +#endif /*RCC_PLLSRC_PREDIV1_SUPPORT*/ + + /* Enable PLL and switch system clock to PLL */ + status = UTILS_EnablePLLAndSwitchSystem(pllfreq, UTILS_ClkInitStruct); + 80012c0: 230f movs r3, #15 + 80012c2: 18fc adds r4, r7, r3 + 80012c4: 683a ldr r2, [r7, #0] + 80012c6: 68bb ldr r3, [r7, #8] + 80012c8: 0011 movs r1, r2 + 80012ca: 0018 movs r0, r3 + 80012cc: f000 f8be bl 800144c <UTILS_EnablePLLAndSwitchSystem> + 80012d0: 0003 movs r3, r0 + 80012d2: 7023 strb r3, [r4, #0] + 80012d4: e003 b.n 80012de <LL_PLL_ConfigSystemClock_HSI+0x7a> + } + else + { + /* Current PLL configuration cannot be modified */ + status = ERROR; + 80012d6: 230f movs r3, #15 + 80012d8: 18fb adds r3, r7, r3 + 80012da: 2200 movs r2, #0 + 80012dc: 701a strb r2, [r3, #0] + } + + return status; + 80012de: 230f movs r3, #15 + 80012e0: 18fb adds r3, r7, r3 + 80012e2: 781b ldrb r3, [r3, #0] +} + 80012e4: 0018 movs r0, r3 + 80012e6: 46bd mov sp, r7 + 80012e8: b005 add sp, #20 + 80012ea: bd90 pop {r4, r7, pc} + 80012ec: 007a1200 .word 0x007a1200 + +080012f0 <LL_PLL_ConfigSystemClock_HSE>: + * - SUCCESS: Max frequency configuration done + * - ERROR: Max frequency configuration not done + */ +ErrorStatus LL_PLL_ConfigSystemClock_HSE(uint32_t HSEFrequency, uint32_t HSEBypass, + LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct, LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct) +{ + 80012f0: b590 push {r4, r7, lr} + 80012f2: b087 sub sp, #28 + 80012f4: af00 add r7, sp, #0 + 80012f6: 60f8 str r0, [r7, #12] + 80012f8: 60b9 str r1, [r7, #8] + 80012fa: 607a str r2, [r7, #4] + 80012fc: 603b str r3, [r7, #0] + ErrorStatus status = SUCCESS; + 80012fe: 2317 movs r3, #23 + 8001300: 18fb adds r3, r7, r3 + 8001302: 2201 movs r2, #1 + 8001304: 701a strb r2, [r3, #0] + uint32_t pllfreq = 0U; + 8001306: 2300 movs r3, #0 + 8001308: 613b str r3, [r7, #16] + /* Check the parameters */ + assert_param(IS_LL_UTILS_HSE_FREQUENCY(HSEFrequency)); + assert_param(IS_LL_UTILS_HSE_BYPASS(HSEBypass)); + + /* Check if one of the PLL is enabled */ + if (UTILS_PLL_IsBusy() == SUCCESS) + 800130a: f000 f88c bl 8001426 <UTILS_PLL_IsBusy> + 800130e: 0003 movs r3, r0 + 8001310: 2b01 cmp r3, #1 + 8001312: d132 bne.n 800137a <LL_PLL_ConfigSystemClock_HSE+0x8a> +#else + assert_param(IS_LL_UTILS_PREDIV_VALUE(UTILS_PLLInitStruct->Prediv)); +#endif /*RCC_PLLSRC_PREDIV1_SUPPORT*/ + + /* Calculate the new PLL output frequency */ + pllfreq = UTILS_GetPLLOutputFrequency(HSEFrequency, UTILS_PLLInitStruct); + 8001314: 687a ldr r2, [r7, #4] + 8001316: 68fb ldr r3, [r7, #12] + 8001318: 0011 movs r1, r2 + 800131a: 0018 movs r0, r3 + 800131c: f000 f866 bl 80013ec <UTILS_GetPLLOutputFrequency> + 8001320: 0003 movs r3, r0 + 8001322: 613b str r3, [r7, #16] + + /* Enable HSE if not enabled */ + if (LL_RCC_HSE_IsReady() != 1U) + 8001324: f7ff fe60 bl 8000fe8 <LL_RCC_HSE_IsReady> + 8001328: 0003 movs r3, r0 + 800132a: 2b01 cmp r3, #1 + 800132c: d00f beq.n 800134e <LL_PLL_ConfigSystemClock_HSE+0x5e> + { + /* Check if need to enable HSE bypass feature or not */ + if (HSEBypass == LL_UTILS_HSEBYPASS_ON) + 800132e: 68bb ldr r3, [r7, #8] + 8001330: 2b01 cmp r3, #1 + 8001332: d102 bne.n 800133a <LL_PLL_ConfigSystemClock_HSE+0x4a> + { + LL_RCC_HSE_EnableBypass(); + 8001334: f7ff fe2c bl 8000f90 <LL_RCC_HSE_EnableBypass> + 8001338: e001 b.n 800133e <LL_PLL_ConfigSystemClock_HSE+0x4e> + } + else + { + LL_RCC_HSE_DisableBypass(); + 800133a: f7ff fe37 bl 8000fac <LL_RCC_HSE_DisableBypass> + } + + /* Enable HSE */ + LL_RCC_HSE_Enable(); + 800133e: f7ff fe45 bl 8000fcc <LL_RCC_HSE_Enable> + while (LL_RCC_HSE_IsReady() != 1U) + 8001342: 46c0 nop ; (mov r8, r8) + 8001344: f7ff fe50 bl 8000fe8 <LL_RCC_HSE_IsReady> + 8001348: 0003 movs r3, r0 + 800134a: 2b01 cmp r3, #1 + 800134c: d1fa bne.n 8001344 <LL_PLL_ConfigSystemClock_HSE+0x54> + + /* Configure PLL */ +#if defined(RCC_PLLSRC_PREDIV1_SUPPORT) + LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE, UTILS_PLLInitStruct->PLLMul, UTILS_PLLInitStruct->PLLDiv); +#else + LL_RCC_PLL_ConfigDomain_SYS((RCC_CFGR_PLLSRC_HSE_PREDIV | UTILS_PLLInitStruct->Prediv), UTILS_PLLInitStruct->PLLMul); + 800134e: 687b ldr r3, [r7, #4] + 8001350: 685b ldr r3, [r3, #4] + 8001352: 2280 movs r2, #128 ; 0x80 + 8001354: 0252 lsls r2, r2, #9 + 8001356: 431a orrs r2, r3 + 8001358: 687b ldr r3, [r7, #4] + 800135a: 681b ldr r3, [r3, #0] + 800135c: 0019 movs r1, r3 + 800135e: 0010 movs r0, r2 + 8001360: f7ff fee0 bl 8001124 <LL_RCC_PLL_ConfigDomain_SYS> +#endif /*RCC_PLLSRC_PREDIV1_SUPPORT*/ + + /* Enable PLL and switch system clock to PLL */ + status = UTILS_EnablePLLAndSwitchSystem(pllfreq, UTILS_ClkInitStruct); + 8001364: 2317 movs r3, #23 + 8001366: 18fc adds r4, r7, r3 + 8001368: 683a ldr r2, [r7, #0] + 800136a: 693b ldr r3, [r7, #16] + 800136c: 0011 movs r1, r2 + 800136e: 0018 movs r0, r3 + 8001370: f000 f86c bl 800144c <UTILS_EnablePLLAndSwitchSystem> + 8001374: 0003 movs r3, r0 + 8001376: 7023 strb r3, [r4, #0] + 8001378: e003 b.n 8001382 <LL_PLL_ConfigSystemClock_HSE+0x92> + } + else + { + /* Current PLL configuration cannot be modified */ + status = ERROR; + 800137a: 2317 movs r3, #23 + 800137c: 18fb adds r3, r7, r3 + 800137e: 2200 movs r2, #0 + 8001380: 701a strb r2, [r3, #0] + } + + return status; + 8001382: 2317 movs r3, #23 + 8001384: 18fb adds r3, r7, r3 + 8001386: 781b ldrb r3, [r3, #0] +} + 8001388: 0018 movs r0, r3 + 800138a: 46bd mov sp, r7 + 800138c: b007 add sp, #28 + 800138e: bd90 pop {r4, r7, pc} + +08001390 <UTILS_SetFlashLatency>: + * @retval An ErrorStatus enumeration value: + * - SUCCESS: Latency has been modified + * - ERROR: Latency cannot be modified + */ +static ErrorStatus UTILS_SetFlashLatency(uint32_t Frequency) +{ + 8001390: b580 push {r7, lr} + 8001392: b084 sub sp, #16 + 8001394: af00 add r7, sp, #0 + 8001396: 6078 str r0, [r7, #4] + ErrorStatus status = SUCCESS; + 8001398: 210f movs r1, #15 + 800139a: 187b adds r3, r7, r1 + 800139c: 2201 movs r2, #1 + 800139e: 701a strb r2, [r3, #0] + + uint32_t latency = LL_FLASH_LATENCY_0; /* default value 0WS */ + 80013a0: 2300 movs r3, #0 + 80013a2: 60bb str r3, [r7, #8] + + /* Frequency cannot be equal to 0 */ + if (Frequency == 0U) + 80013a4: 687b ldr r3, [r7, #4] + 80013a6: 2b00 cmp r3, #0 + 80013a8: d103 bne.n 80013b2 <UTILS_SetFlashLatency+0x22> + { + status = ERROR; + 80013aa: 187b adds r3, r7, r1 + 80013ac: 2200 movs r2, #0 + 80013ae: 701a strb r2, [r3, #0] + 80013b0: e013 b.n 80013da <UTILS_SetFlashLatency+0x4a> + } + else + { + if (Frequency > UTILS_LATENCY1_FREQ) + 80013b2: 687b ldr r3, [r7, #4] + 80013b4: 4a0c ldr r2, [pc, #48] ; (80013e8 <UTILS_SetFlashLatency+0x58>) + 80013b6: 4293 cmp r3, r2 + 80013b8: d901 bls.n 80013be <UTILS_SetFlashLatency+0x2e> + { + /* 24 < SYSCLK <= 48 => 1WS (2 CPU cycles) */ + latency = LL_FLASH_LATENCY_1; + 80013ba: 2301 movs r3, #1 + 80013bc: 60bb str r3, [r7, #8] + } + /* else SYSCLK < 24MHz default LL_FLASH_LATENCY_0 0WS */ + + LL_FLASH_SetLatency(latency); + 80013be: 68bb ldr r3, [r7, #8] + 80013c0: 0018 movs r0, r3 + 80013c2: f7ff feef bl 80011a4 <LL_FLASH_SetLatency> + + /* Check that the new number of wait states is taken into account to access the Flash + memory by reading the FLASH_ACR register */ + if (LL_FLASH_GetLatency() != latency) + 80013c6: f7ff ff01 bl 80011cc <LL_FLASH_GetLatency> + 80013ca: 0002 movs r2, r0 + 80013cc: 68bb ldr r3, [r7, #8] + 80013ce: 4293 cmp r3, r2 + 80013d0: d003 beq.n 80013da <UTILS_SetFlashLatency+0x4a> + { + status = ERROR; + 80013d2: 230f movs r3, #15 + 80013d4: 18fb adds r3, r7, r3 + 80013d6: 2200 movs r2, #0 + 80013d8: 701a strb r2, [r3, #0] + } + } + return status; + 80013da: 230f movs r3, #15 + 80013dc: 18fb adds r3, r7, r3 + 80013de: 781b ldrb r3, [r3, #0] +} + 80013e0: 0018 movs r0, r3 + 80013e2: 46bd mov sp, r7 + 80013e4: b004 add sp, #16 + 80013e6: bd80 pop {r7, pc} + 80013e8: 016e3600 .word 0x016e3600 + +080013ec <UTILS_GetPLLOutputFrequency>: + * @param UTILS_PLLInitStruct pointer to a @ref LL_UTILS_PLLInitTypeDef structure that contains + * the configuration information for the PLL. + * @retval PLL output frequency (in Hz) + */ +static uint32_t UTILS_GetPLLOutputFrequency(uint32_t PLL_InputFrequency, LL_UTILS_PLLInitTypeDef *UTILS_PLLInitStruct) +{ + 80013ec: b580 push {r7, lr} + 80013ee: b084 sub sp, #16 + 80013f0: af00 add r7, sp, #0 + 80013f2: 6078 str r0, [r7, #4] + 80013f4: 6039 str r1, [r7, #0] + uint32_t pllfreq = 0U; + 80013f6: 2300 movs r3, #0 + 80013f8: 60fb str r3, [r7, #12] + /* The application software must set correctly the PLL multiplication factor to + be in the range 16-48MHz */ +#if defined(RCC_PLLSRC_PREDIV1_SUPPORT) + pllfreq = __LL_RCC_CALC_PLLCLK_FREQ(PLL_InputFrequency, UTILS_PLLInitStruct->PLLMul, UTILS_PLLInitStruct->PLLDiv); +#else + pllfreq = __LL_RCC_CALC_PLLCLK_FREQ(PLL_InputFrequency / (UTILS_PLLInitStruct->Prediv + 1U), UTILS_PLLInitStruct->PLLMul); + 80013fa: 683b ldr r3, [r7, #0] + 80013fc: 685b ldr r3, [r3, #4] + 80013fe: 3301 adds r3, #1 + 8001400: 0019 movs r1, r3 + 8001402: 6878 ldr r0, [r7, #4] + 8001404: f000 f8d0 bl 80015a8 <__udivsi3> + 8001408: 0003 movs r3, r0 + 800140a: 0019 movs r1, r3 + 800140c: 683b ldr r3, [r7, #0] + 800140e: 681b ldr r3, [r3, #0] + 8001410: 0c9b lsrs r3, r3, #18 + 8001412: 220f movs r2, #15 + 8001414: 4013 ands r3, r2 + 8001416: 3302 adds r3, #2 + 8001418: 434b muls r3, r1 + 800141a: 60fb str r3, [r7, #12] +#endif /*RCC_PLLSRC_PREDIV1_SUPPORT*/ + assert_param(IS_LL_UTILS_PLL_FREQUENCY(pllfreq)); + + return pllfreq; + 800141c: 68fb ldr r3, [r7, #12] +} + 800141e: 0018 movs r0, r3 + 8001420: 46bd mov sp, r7 + 8001422: b004 add sp, #16 + 8001424: bd80 pop {r7, pc} + +08001426 <UTILS_PLL_IsBusy>: + * @retval An ErrorStatus enumeration value: + * - SUCCESS: PLL modification can be done + * - ERROR: PLL is busy + */ +static ErrorStatus UTILS_PLL_IsBusy(void) +{ + 8001426: b580 push {r7, lr} + 8001428: b082 sub sp, #8 + 800142a: af00 add r7, sp, #0 + ErrorStatus status = SUCCESS; + 800142c: 1dfb adds r3, r7, #7 + 800142e: 2201 movs r2, #1 + 8001430: 701a strb r2, [r3, #0] + + /* Check if PLL is busy*/ + if (LL_RCC_PLL_IsReady() != 0U) + 8001432: f7ff fe63 bl 80010fc <LL_RCC_PLL_IsReady> + 8001436: 1e03 subs r3, r0, #0 + 8001438: d002 beq.n 8001440 <UTILS_PLL_IsBusy+0x1a> + { + /* PLL configuration cannot be modified */ + status = ERROR; + 800143a: 1dfb adds r3, r7, #7 + 800143c: 2200 movs r2, #0 + 800143e: 701a strb r2, [r3, #0] + } + + + return status; + 8001440: 1dfb adds r3, r7, #7 + 8001442: 781b ldrb r3, [r3, #0] +} + 8001444: 0018 movs r0, r3 + 8001446: 46bd mov sp, r7 + 8001448: b002 add sp, #8 + 800144a: bd80 pop {r7, pc} + +0800144c <UTILS_EnablePLLAndSwitchSystem>: + * @retval An ErrorStatus enumeration value: + * - SUCCESS: No problem to switch system to PLL + * - ERROR: Problem to switch system to PLL + */ +static ErrorStatus UTILS_EnablePLLAndSwitchSystem(uint32_t SYSCLK_Frequency, LL_UTILS_ClkInitTypeDef *UTILS_ClkInitStruct) +{ + 800144c: b590 push {r4, r7, lr} + 800144e: b085 sub sp, #20 + 8001450: af00 add r7, sp, #0 + 8001452: 6078 str r0, [r7, #4] + 8001454: 6039 str r1, [r7, #0] + ErrorStatus status = SUCCESS; + 8001456: 200f movs r0, #15 + 8001458: 183b adds r3, r7, r0 + 800145a: 2201 movs r2, #1 + 800145c: 701a strb r2, [r3, #0] + uint32_t sysclk_frequency_current = 0U; + 800145e: 2300 movs r3, #0 + 8001460: 60bb str r3, [r7, #8] + + assert_param(IS_LL_UTILS_SYSCLK_DIV(UTILS_ClkInitStruct->AHBCLKDivider)); + assert_param(IS_LL_UTILS_APB1_DIV(UTILS_ClkInitStruct->APB1CLKDivider)); + + /* Calculate current SYSCLK frequency */ + sysclk_frequency_current = (SystemCoreClock << AHBPrescTable[(UTILS_ClkInitStruct->AHBCLKDivider & RCC_CFGR_HPRE) >> RCC_POSITION_HPRE]); + 8001462: 4b2e ldr r3, [pc, #184] ; (800151c <UTILS_EnablePLLAndSwitchSystem+0xd0>) + 8001464: 681a ldr r2, [r3, #0] + 8001466: 683b ldr r3, [r7, #0] + 8001468: 681b ldr r3, [r3, #0] + 800146a: 091b lsrs r3, r3, #4 + 800146c: 210f movs r1, #15 + 800146e: 400b ands r3, r1 + 8001470: 492b ldr r1, [pc, #172] ; (8001520 <UTILS_EnablePLLAndSwitchSystem+0xd4>) + 8001472: 5ccb ldrb r3, [r1, r3] + 8001474: 409a lsls r2, r3 + 8001476: 0013 movs r3, r2 + 8001478: 60bb str r3, [r7, #8] + + /* Increasing the number of wait states because of higher CPU frequency */ + if (sysclk_frequency_current < SYSCLK_Frequency) + 800147a: 68ba ldr r2, [r7, #8] + 800147c: 687b ldr r3, [r7, #4] + 800147e: 429a cmp r2, r3 + 8001480: d206 bcs.n 8001490 <UTILS_EnablePLLAndSwitchSystem+0x44> + { + /* Set FLASH latency to highest latency */ + status = UTILS_SetFlashLatency(SYSCLK_Frequency); + 8001482: 183c adds r4, r7, r0 + 8001484: 687b ldr r3, [r7, #4] + 8001486: 0018 movs r0, r3 + 8001488: f7ff ff82 bl 8001390 <UTILS_SetFlashLatency> + 800148c: 0003 movs r3, r0 + 800148e: 7023 strb r3, [r4, #0] + } + + /* Update system clock configuration */ + if (status == SUCCESS) + 8001490: 230f movs r3, #15 + 8001492: 18fb adds r3, r7, r3 + 8001494: 781b ldrb r3, [r3, #0] + 8001496: 2b01 cmp r3, #1 + 8001498: d11a bne.n 80014d0 <UTILS_EnablePLLAndSwitchSystem+0x84> + { + /* Enable PLL */ + LL_RCC_PLL_Enable(); + 800149a: f7ff fe21 bl 80010e0 <LL_RCC_PLL_Enable> + while (LL_RCC_PLL_IsReady() != 1U) + 800149e: 46c0 nop ; (mov r8, r8) + 80014a0: f7ff fe2c bl 80010fc <LL_RCC_PLL_IsReady> + 80014a4: 0003 movs r3, r0 + 80014a6: 2b01 cmp r3, #1 + 80014a8: d1fa bne.n 80014a0 <UTILS_EnablePLLAndSwitchSystem+0x54> + { + /* Wait for PLL ready */ + } + + /* Sysclk activation on the main PLL */ + LL_RCC_SetAHBPrescaler(UTILS_ClkInitStruct->AHBCLKDivider); + 80014aa: 683b ldr r3, [r7, #0] + 80014ac: 681b ldr r3, [r3, #0] + 80014ae: 0018 movs r0, r3 + 80014b0: f7ff fdec bl 800108c <LL_RCC_SetAHBPrescaler> + LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL); + 80014b4: 2002 movs r0, #2 + 80014b6: f7ff fdc9 bl 800104c <LL_RCC_SetSysClkSource> + while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) + 80014ba: 46c0 nop ; (mov r8, r8) + 80014bc: f7ff fdda bl 8001074 <LL_RCC_GetSysClkSource> + 80014c0: 0003 movs r3, r0 + 80014c2: 2b08 cmp r3, #8 + 80014c4: d1fa bne.n 80014bc <UTILS_EnablePLLAndSwitchSystem+0x70> + { + /* Wait for system clock switch to PLL */ + } + + /* Set APB1 & APB2 prescaler*/ + LL_RCC_SetAPB1Prescaler(UTILS_ClkInitStruct->APB1CLKDivider); + 80014c6: 683b ldr r3, [r7, #0] + 80014c8: 685b ldr r3, [r3, #4] + 80014ca: 0018 movs r0, r3 + 80014cc: f7ff fdf2 bl 80010b4 <LL_RCC_SetAPB1Prescaler> + } + + /* Decreasing the number of wait states because of lower CPU frequency */ + if (sysclk_frequency_current > SYSCLK_Frequency) + 80014d0: 68ba ldr r2, [r7, #8] + 80014d2: 687b ldr r3, [r7, #4] + 80014d4: 429a cmp r2, r3 + 80014d6: d907 bls.n 80014e8 <UTILS_EnablePLLAndSwitchSystem+0x9c> + { + /* Set FLASH latency to lowest latency */ + status = UTILS_SetFlashLatency(SYSCLK_Frequency); + 80014d8: 230f movs r3, #15 + 80014da: 18fc adds r4, r7, r3 + 80014dc: 687b ldr r3, [r7, #4] + 80014de: 0018 movs r0, r3 + 80014e0: f7ff ff56 bl 8001390 <UTILS_SetFlashLatency> + 80014e4: 0003 movs r3, r0 + 80014e6: 7023 strb r3, [r4, #0] + } + + /* Update SystemCoreClock variable */ + if (status == SUCCESS) + 80014e8: 230f movs r3, #15 + 80014ea: 18fb adds r3, r7, r3 + 80014ec: 781b ldrb r3, [r3, #0] + 80014ee: 2b01 cmp r3, #1 + 80014f0: d10c bne.n 800150c <UTILS_EnablePLLAndSwitchSystem+0xc0> + { + LL_SetSystemCoreClock(__LL_RCC_CALC_HCLK_FREQ(SYSCLK_Frequency, UTILS_ClkInitStruct->AHBCLKDivider)); + 80014f2: 683b ldr r3, [r7, #0] + 80014f4: 681b ldr r3, [r3, #0] + 80014f6: 091b lsrs r3, r3, #4 + 80014f8: 220f movs r2, #15 + 80014fa: 4013 ands r3, r2 + 80014fc: 4a08 ldr r2, [pc, #32] ; (8001520 <UTILS_EnablePLLAndSwitchSystem+0xd4>) + 80014fe: 5cd3 ldrb r3, [r2, r3] + 8001500: 001a movs r2, r3 + 8001502: 687b ldr r3, [r7, #4] + 8001504: 40d3 lsrs r3, r2 + 8001506: 0018 movs r0, r3 + 8001508: f7ff fe9e bl 8001248 <LL_SetSystemCoreClock> + } + + return status; + 800150c: 230f movs r3, #15 + 800150e: 18fb adds r3, r7, r3 + 8001510: 781b ldrb r3, [r3, #0] +} + 8001512: 0018 movs r0, r3 + 8001514: 46bd mov sp, r7 + 8001516: b005 add sp, #20 + 8001518: bd90 pop {r4, r7, pc} + 800151a: 46c0 nop ; (mov r8, r8) + 800151c: 20000000 .word 0x20000000 + 8001520: 080018ec .word 0x080018ec + +08001524 <__sinit>: +#include <stdbool.h> + +int __errno = 0; +void *_impure_ptr = NULL; + +void __sinit(void) { + 8001524: b580 push {r7, lr} + 8001526: af00 add r7, sp, #0 +} + 8001528: 46c0 nop ; (mov r8, r8) + 800152a: 46bd mov sp, r7 + 800152c: bd80 pop {r7, pc} + +0800152e <memset>: + +void *memset(void *s, int c, size_t n) { + 800152e: b580 push {r7, lr} + 8001530: b086 sub sp, #24 + 8001532: af00 add r7, sp, #0 + 8001534: 60f8 str r0, [r7, #12] + 8001536: 60b9 str r1, [r7, #8] + 8001538: 607a str r2, [r7, #4] + char *end = (char *)s + n; + 800153a: 68fa ldr r2, [r7, #12] + 800153c: 687b ldr r3, [r7, #4] + 800153e: 18d3 adds r3, r2, r3 + 8001540: 613b str r3, [r7, #16] + for (char *p = (char *)s; p < end; p++) + 8001542: 68fb ldr r3, [r7, #12] + 8001544: 617b str r3, [r7, #20] + 8001546: e006 b.n 8001556 <memset+0x28> + *p = (char)c; + 8001548: 68bb ldr r3, [r7, #8] + 800154a: b2da uxtb r2, r3 + 800154c: 697b ldr r3, [r7, #20] + 800154e: 701a strb r2, [r3, #0] + for (char *p = (char *)s; p < end; p++) + 8001550: 697b ldr r3, [r7, #20] + 8001552: 3301 adds r3, #1 + 8001554: 617b str r3, [r7, #20] + 8001556: 697a ldr r2, [r7, #20] + 8001558: 693b ldr r3, [r7, #16] + 800155a: 429a cmp r2, r3 + 800155c: d3f4 bcc.n 8001548 <memset+0x1a> + return s; + 800155e: 68fb ldr r3, [r7, #12] +} + 8001560: 0018 movs r0, r3 + 8001562: 46bd mov sp, r7 + 8001564: b006 add sp, #24 + 8001566: bd80 pop {r7, pc} + +08001568 <strlen>: + +size_t strlen(const char *s) { + 8001568: b580 push {r7, lr} + 800156a: b084 sub sp, #16 + 800156c: af00 add r7, sp, #0 + 800156e: 6078 str r0, [r7, #4] + const char *start = s; + 8001570: 687b ldr r3, [r7, #4] + 8001572: 60fb str r3, [r7, #12] + while (*s++); + 8001574: 46c0 nop ; (mov r8, r8) + 8001576: 687b ldr r3, [r7, #4] + 8001578: 1c5a adds r2, r3, #1 + 800157a: 607a str r2, [r7, #4] + 800157c: 781b ldrb r3, [r3, #0] + 800157e: 2b00 cmp r3, #0 + 8001580: d1f9 bne.n 8001576 <strlen+0xe> + return s - start - 1; + 8001582: 687a ldr r2, [r7, #4] + 8001584: 68fb ldr r3, [r7, #12] + 8001586: 1ad3 subs r3, r2, r3 + 8001588: 3b01 subs r3, #1 +} + 800158a: 0018 movs r0, r3 + 800158c: 46bd mov sp, r7 + 800158e: b004 add sp, #16 + 8001590: bd80 pop {r7, pc} + +08001592 <__assert_func>: + +void __assert_func(bool value) { + 8001592: b580 push {r7, lr} + 8001594: b082 sub sp, #8 + 8001596: af00 add r7, sp, #0 + 8001598: 0002 movs r2, r0 + 800159a: 1dfb adds r3, r7, #7 + 800159c: 701a strb r2, [r3, #0] +} + 800159e: 46c0 nop ; (mov r8, r8) + 80015a0: 46bd mov sp, r7 + 80015a2: b002 add sp, #8 + 80015a4: bd80 pop {r7, pc} + ... + +080015a8 <__udivsi3>: + 80015a8: 2200 movs r2, #0 + 80015aa: 0843 lsrs r3, r0, #1 + 80015ac: 428b cmp r3, r1 + 80015ae: d374 bcc.n 800169a <__udivsi3+0xf2> + 80015b0: 0903 lsrs r3, r0, #4 + 80015b2: 428b cmp r3, r1 + 80015b4: d35f bcc.n 8001676 <__udivsi3+0xce> + 80015b6: 0a03 lsrs r3, r0, #8 + 80015b8: 428b cmp r3, r1 + 80015ba: d344 bcc.n 8001646 <__udivsi3+0x9e> + 80015bc: 0b03 lsrs r3, r0, #12 + 80015be: 428b cmp r3, r1 + 80015c0: d328 bcc.n 8001614 <__udivsi3+0x6c> + 80015c2: 0c03 lsrs r3, r0, #16 + 80015c4: 428b cmp r3, r1 + 80015c6: d30d bcc.n 80015e4 <__udivsi3+0x3c> + 80015c8: 22ff movs r2, #255 ; 0xff + 80015ca: 0209 lsls r1, r1, #8 + 80015cc: ba12 rev r2, r2 + 80015ce: 0c03 lsrs r3, r0, #16 + 80015d0: 428b cmp r3, r1 + 80015d2: d302 bcc.n 80015da <__udivsi3+0x32> + 80015d4: 1212 asrs r2, r2, #8 + 80015d6: 0209 lsls r1, r1, #8 + 80015d8: d065 beq.n 80016a6 <__udivsi3+0xfe> + 80015da: 0b03 lsrs r3, r0, #12 + 80015dc: 428b cmp r3, r1 + 80015de: d319 bcc.n 8001614 <__udivsi3+0x6c> + 80015e0: e000 b.n 80015e4 <__udivsi3+0x3c> + 80015e2: 0a09 lsrs r1, r1, #8 + 80015e4: 0bc3 lsrs r3, r0, #15 + 80015e6: 428b cmp r3, r1 + 80015e8: d301 bcc.n 80015ee <__udivsi3+0x46> + 80015ea: 03cb lsls r3, r1, #15 + 80015ec: 1ac0 subs r0, r0, r3 + 80015ee: 4152 adcs r2, r2 + 80015f0: 0b83 lsrs r3, r0, #14 + 80015f2: 428b cmp r3, r1 + 80015f4: d301 bcc.n 80015fa <__udivsi3+0x52> + 80015f6: 038b lsls r3, r1, #14 + 80015f8: 1ac0 subs r0, r0, r3 + 80015fa: 4152 adcs r2, r2 + 80015fc: 0b43 lsrs r3, r0, #13 + 80015fe: 428b cmp r3, r1 + 8001600: d301 bcc.n 8001606 <__udivsi3+0x5e> + 8001602: 034b lsls r3, r1, #13 + 8001604: 1ac0 subs r0, r0, r3 + 8001606: 4152 adcs r2, r2 + 8001608: 0b03 lsrs r3, r0, #12 + 800160a: 428b cmp r3, r1 + 800160c: d301 bcc.n 8001612 <__udivsi3+0x6a> + 800160e: 030b lsls r3, r1, #12 + 8001610: 1ac0 subs r0, r0, r3 + 8001612: 4152 adcs r2, r2 + 8001614: 0ac3 lsrs r3, r0, #11 + 8001616: 428b cmp r3, r1 + 8001618: d301 bcc.n 800161e <__udivsi3+0x76> + 800161a: 02cb lsls r3, r1, #11 + 800161c: 1ac0 subs r0, r0, r3 + 800161e: 4152 adcs r2, r2 + 8001620: 0a83 lsrs r3, r0, #10 + 8001622: 428b cmp r3, r1 + 8001624: d301 bcc.n 800162a <__udivsi3+0x82> + 8001626: 028b lsls r3, r1, #10 + 8001628: 1ac0 subs r0, r0, r3 + 800162a: 4152 adcs r2, r2 + 800162c: 0a43 lsrs r3, r0, #9 + 800162e: 428b cmp r3, r1 + 8001630: d301 bcc.n 8001636 <__udivsi3+0x8e> + 8001632: 024b lsls r3, r1, #9 + 8001634: 1ac0 subs r0, r0, r3 + 8001636: 4152 adcs r2, r2 + 8001638: 0a03 lsrs r3, r0, #8 + 800163a: 428b cmp r3, r1 + 800163c: d301 bcc.n 8001642 <__udivsi3+0x9a> + 800163e: 020b lsls r3, r1, #8 + 8001640: 1ac0 subs r0, r0, r3 + 8001642: 4152 adcs r2, r2 + 8001644: d2cd bcs.n 80015e2 <__udivsi3+0x3a> + 8001646: 09c3 lsrs r3, r0, #7 + 8001648: 428b cmp r3, r1 + 800164a: d301 bcc.n 8001650 <__udivsi3+0xa8> + 800164c: 01cb lsls r3, r1, #7 + 800164e: 1ac0 subs r0, r0, r3 + 8001650: 4152 adcs r2, r2 + 8001652: 0983 lsrs r3, r0, #6 + 8001654: 428b cmp r3, r1 + 8001656: d301 bcc.n 800165c <__udivsi3+0xb4> + 8001658: 018b lsls r3, r1, #6 + 800165a: 1ac0 subs r0, r0, r3 + 800165c: 4152 adcs r2, r2 + 800165e: 0943 lsrs r3, r0, #5 + 8001660: 428b cmp r3, r1 + 8001662: d301 bcc.n 8001668 <__udivsi3+0xc0> + 8001664: 014b lsls r3, r1, #5 + 8001666: 1ac0 subs r0, r0, r3 + 8001668: 4152 adcs r2, r2 + 800166a: 0903 lsrs r3, r0, #4 + 800166c: 428b cmp r3, r1 + 800166e: d301 bcc.n 8001674 <__udivsi3+0xcc> + 8001670: 010b lsls r3, r1, #4 + 8001672: 1ac0 subs r0, r0, r3 + 8001674: 4152 adcs r2, r2 + 8001676: 08c3 lsrs r3, r0, #3 + 8001678: 428b cmp r3, r1 + 800167a: d301 bcc.n 8001680 <__udivsi3+0xd8> + 800167c: 00cb lsls r3, r1, #3 + 800167e: 1ac0 subs r0, r0, r3 + 8001680: 4152 adcs r2, r2 + 8001682: 0883 lsrs r3, r0, #2 + 8001684: 428b cmp r3, r1 + 8001686: d301 bcc.n 800168c <__udivsi3+0xe4> + 8001688: 008b lsls r3, r1, #2 + 800168a: 1ac0 subs r0, r0, r3 + 800168c: 4152 adcs r2, r2 + 800168e: 0843 lsrs r3, r0, #1 + 8001690: 428b cmp r3, r1 + 8001692: d301 bcc.n 8001698 <__udivsi3+0xf0> + 8001694: 004b lsls r3, r1, #1 + 8001696: 1ac0 subs r0, r0, r3 + 8001698: 4152 adcs r2, r2 + 800169a: 1a41 subs r1, r0, r1 + 800169c: d200 bcs.n 80016a0 <__udivsi3+0xf8> + 800169e: 4601 mov r1, r0 + 80016a0: 4152 adcs r2, r2 + 80016a2: 4610 mov r0, r2 + 80016a4: 4770 bx lr + 80016a6: e7ff b.n 80016a8 <__udivsi3+0x100> + 80016a8: b501 push {r0, lr} + 80016aa: 2000 movs r0, #0 + 80016ac: f000 f8f0 bl 8001890 <__aeabi_idiv0> + 80016b0: bd02 pop {r1, pc} + 80016b2: 46c0 nop ; (mov r8, r8) + +080016b4 <__aeabi_uidivmod>: + 80016b4: 2900 cmp r1, #0 + 80016b6: d0f7 beq.n 80016a8 <__udivsi3+0x100> + 80016b8: e776 b.n 80015a8 <__udivsi3> + 80016ba: 4770 bx lr + +080016bc <__divsi3>: + 80016bc: 4603 mov r3, r0 + 80016be: 430b orrs r3, r1 + 80016c0: d47f bmi.n 80017c2 <__divsi3+0x106> + 80016c2: 2200 movs r2, #0 + 80016c4: 0843 lsrs r3, r0, #1 + 80016c6: 428b cmp r3, r1 + 80016c8: d374 bcc.n 80017b4 <__divsi3+0xf8> + 80016ca: 0903 lsrs r3, r0, #4 + 80016cc: 428b cmp r3, r1 + 80016ce: d35f bcc.n 8001790 <__divsi3+0xd4> + 80016d0: 0a03 lsrs r3, r0, #8 + 80016d2: 428b cmp r3, r1 + 80016d4: d344 bcc.n 8001760 <__divsi3+0xa4> + 80016d6: 0b03 lsrs r3, r0, #12 + 80016d8: 428b cmp r3, r1 + 80016da: d328 bcc.n 800172e <__divsi3+0x72> + 80016dc: 0c03 lsrs r3, r0, #16 + 80016de: 428b cmp r3, r1 + 80016e0: d30d bcc.n 80016fe <__divsi3+0x42> + 80016e2: 22ff movs r2, #255 ; 0xff + 80016e4: 0209 lsls r1, r1, #8 + 80016e6: ba12 rev r2, r2 + 80016e8: 0c03 lsrs r3, r0, #16 + 80016ea: 428b cmp r3, r1 + 80016ec: d302 bcc.n 80016f4 <__divsi3+0x38> + 80016ee: 1212 asrs r2, r2, #8 + 80016f0: 0209 lsls r1, r1, #8 + 80016f2: d065 beq.n 80017c0 <__divsi3+0x104> + 80016f4: 0b03 lsrs r3, r0, #12 + 80016f6: 428b cmp r3, r1 + 80016f8: d319 bcc.n 800172e <__divsi3+0x72> + 80016fa: e000 b.n 80016fe <__divsi3+0x42> + 80016fc: 0a09 lsrs r1, r1, #8 + 80016fe: 0bc3 lsrs r3, r0, #15 + 8001700: 428b cmp r3, r1 + 8001702: d301 bcc.n 8001708 <__divsi3+0x4c> + 8001704: 03cb lsls r3, r1, #15 + 8001706: 1ac0 subs r0, r0, r3 + 8001708: 4152 adcs r2, r2 + 800170a: 0b83 lsrs r3, r0, #14 + 800170c: 428b cmp r3, r1 + 800170e: d301 bcc.n 8001714 <__divsi3+0x58> + 8001710: 038b lsls r3, r1, #14 + 8001712: 1ac0 subs r0, r0, r3 + 8001714: 4152 adcs r2, r2 + 8001716: 0b43 lsrs r3, r0, #13 + 8001718: 428b cmp r3, r1 + 800171a: d301 bcc.n 8001720 <__divsi3+0x64> + 800171c: 034b lsls r3, r1, #13 + 800171e: 1ac0 subs r0, r0, r3 + 8001720: 4152 adcs r2, r2 + 8001722: 0b03 lsrs r3, r0, #12 + 8001724: 428b cmp r3, r1 + 8001726: d301 bcc.n 800172c <__divsi3+0x70> + 8001728: 030b lsls r3, r1, #12 + 800172a: 1ac0 subs r0, r0, r3 + 800172c: 4152 adcs r2, r2 + 800172e: 0ac3 lsrs r3, r0, #11 + 8001730: 428b cmp r3, r1 + 8001732: d301 bcc.n 8001738 <__divsi3+0x7c> + 8001734: 02cb lsls r3, r1, #11 + 8001736: 1ac0 subs r0, r0, r3 + 8001738: 4152 adcs r2, r2 + 800173a: 0a83 lsrs r3, r0, #10 + 800173c: 428b cmp r3, r1 + 800173e: d301 bcc.n 8001744 <__divsi3+0x88> + 8001740: 028b lsls r3, r1, #10 + 8001742: 1ac0 subs r0, r0, r3 + 8001744: 4152 adcs r2, r2 + 8001746: 0a43 lsrs r3, r0, #9 + 8001748: 428b cmp r3, r1 + 800174a: d301 bcc.n 8001750 <__divsi3+0x94> + 800174c: 024b lsls r3, r1, #9 + 800174e: 1ac0 subs r0, r0, r3 + 8001750: 4152 adcs r2, r2 + 8001752: 0a03 lsrs r3, r0, #8 + 8001754: 428b cmp r3, r1 + 8001756: d301 bcc.n 800175c <__divsi3+0xa0> + 8001758: 020b lsls r3, r1, #8 + 800175a: 1ac0 subs r0, r0, r3 + 800175c: 4152 adcs r2, r2 + 800175e: d2cd bcs.n 80016fc <__divsi3+0x40> + 8001760: 09c3 lsrs r3, r0, #7 + 8001762: 428b cmp r3, r1 + 8001764: d301 bcc.n 800176a <__divsi3+0xae> + 8001766: 01cb lsls r3, r1, #7 + 8001768: 1ac0 subs r0, r0, r3 + 800176a: 4152 adcs r2, r2 + 800176c: 0983 lsrs r3, r0, #6 + 800176e: 428b cmp r3, r1 + 8001770: d301 bcc.n 8001776 <__divsi3+0xba> + 8001772: 018b lsls r3, r1, #6 + 8001774: 1ac0 subs r0, r0, r3 + 8001776: 4152 adcs r2, r2 + 8001778: 0943 lsrs r3, r0, #5 + 800177a: 428b cmp r3, r1 + 800177c: d301 bcc.n 8001782 <__divsi3+0xc6> + 800177e: 014b lsls r3, r1, #5 + 8001780: 1ac0 subs r0, r0, r3 + 8001782: 4152 adcs r2, r2 + 8001784: 0903 lsrs r3, r0, #4 + 8001786: 428b cmp r3, r1 + 8001788: d301 bcc.n 800178e <__divsi3+0xd2> + 800178a: 010b lsls r3, r1, #4 + 800178c: 1ac0 subs r0, r0, r3 + 800178e: 4152 adcs r2, r2 + 8001790: 08c3 lsrs r3, r0, #3 + 8001792: 428b cmp r3, r1 + 8001794: d301 bcc.n 800179a <__divsi3+0xde> + 8001796: 00cb lsls r3, r1, #3 + 8001798: 1ac0 subs r0, r0, r3 + 800179a: 4152 adcs r2, r2 + 800179c: 0883 lsrs r3, r0, #2 + 800179e: 428b cmp r3, r1 + 80017a0: d301 bcc.n 80017a6 <__divsi3+0xea> + 80017a2: 008b lsls r3, r1, #2 + 80017a4: 1ac0 subs r0, r0, r3 + 80017a6: 4152 adcs r2, r2 + 80017a8: 0843 lsrs r3, r0, #1 + 80017aa: 428b cmp r3, r1 + 80017ac: d301 bcc.n 80017b2 <__divsi3+0xf6> + 80017ae: 004b lsls r3, r1, #1 + 80017b0: 1ac0 subs r0, r0, r3 + 80017b2: 4152 adcs r2, r2 + 80017b4: 1a41 subs r1, r0, r1 + 80017b6: d200 bcs.n 80017ba <__divsi3+0xfe> + 80017b8: 4601 mov r1, r0 + 80017ba: 4152 adcs r2, r2 + 80017bc: 4610 mov r0, r2 + 80017be: 4770 bx lr + 80017c0: e05d b.n 800187e <__divsi3+0x1c2> + 80017c2: 0fca lsrs r2, r1, #31 + 80017c4: d000 beq.n 80017c8 <__divsi3+0x10c> + 80017c6: 4249 negs r1, r1 + 80017c8: 1003 asrs r3, r0, #32 + 80017ca: d300 bcc.n 80017ce <__divsi3+0x112> + 80017cc: 4240 negs r0, r0 + 80017ce: 4053 eors r3, r2 + 80017d0: 2200 movs r2, #0 + 80017d2: 469c mov ip, r3 + 80017d4: 0903 lsrs r3, r0, #4 + 80017d6: 428b cmp r3, r1 + 80017d8: d32d bcc.n 8001836 <__divsi3+0x17a> + 80017da: 0a03 lsrs r3, r0, #8 + 80017dc: 428b cmp r3, r1 + 80017de: d312 bcc.n 8001806 <__divsi3+0x14a> + 80017e0: 22fc movs r2, #252 ; 0xfc + 80017e2: 0189 lsls r1, r1, #6 + 80017e4: ba12 rev r2, r2 + 80017e6: 0a03 lsrs r3, r0, #8 + 80017e8: 428b cmp r3, r1 + 80017ea: d30c bcc.n 8001806 <__divsi3+0x14a> + 80017ec: 0189 lsls r1, r1, #6 + 80017ee: 1192 asrs r2, r2, #6 + 80017f0: 428b cmp r3, r1 + 80017f2: d308 bcc.n 8001806 <__divsi3+0x14a> + 80017f4: 0189 lsls r1, r1, #6 + 80017f6: 1192 asrs r2, r2, #6 + 80017f8: 428b cmp r3, r1 + 80017fa: d304 bcc.n 8001806 <__divsi3+0x14a> + 80017fc: 0189 lsls r1, r1, #6 + 80017fe: d03a beq.n 8001876 <__divsi3+0x1ba> + 8001800: 1192 asrs r2, r2, #6 + 8001802: e000 b.n 8001806 <__divsi3+0x14a> + 8001804: 0989 lsrs r1, r1, #6 + 8001806: 09c3 lsrs r3, r0, #7 + 8001808: 428b cmp r3, r1 + 800180a: d301 bcc.n 8001810 <__divsi3+0x154> + 800180c: 01cb lsls r3, r1, #7 + 800180e: 1ac0 subs r0, r0, r3 + 8001810: 4152 adcs r2, r2 + 8001812: 0983 lsrs r3, r0, #6 + 8001814: 428b cmp r3, r1 + 8001816: d301 bcc.n 800181c <__divsi3+0x160> + 8001818: 018b lsls r3, r1, #6 + 800181a: 1ac0 subs r0, r0, r3 + 800181c: 4152 adcs r2, r2 + 800181e: 0943 lsrs r3, r0, #5 + 8001820: 428b cmp r3, r1 + 8001822: d301 bcc.n 8001828 <__divsi3+0x16c> + 8001824: 014b lsls r3, r1, #5 + 8001826: 1ac0 subs r0, r0, r3 + 8001828: 4152 adcs r2, r2 + 800182a: 0903 lsrs r3, r0, #4 + 800182c: 428b cmp r3, r1 + 800182e: d301 bcc.n 8001834 <__divsi3+0x178> + 8001830: 010b lsls r3, r1, #4 + 8001832: 1ac0 subs r0, r0, r3 + 8001834: 4152 adcs r2, r2 + 8001836: 08c3 lsrs r3, r0, #3 + 8001838: 428b cmp r3, r1 + 800183a: d301 bcc.n 8001840 <__divsi3+0x184> + 800183c: 00cb lsls r3, r1, #3 + 800183e: 1ac0 subs r0, r0, r3 + 8001840: 4152 adcs r2, r2 + 8001842: 0883 lsrs r3, r0, #2 + 8001844: 428b cmp r3, r1 + 8001846: d301 bcc.n 800184c <__divsi3+0x190> + 8001848: 008b lsls r3, r1, #2 + 800184a: 1ac0 subs r0, r0, r3 + 800184c: 4152 adcs r2, r2 + 800184e: d2d9 bcs.n 8001804 <__divsi3+0x148> + 8001850: 0843 lsrs r3, r0, #1 + 8001852: 428b cmp r3, r1 + 8001854: d301 bcc.n 800185a <__divsi3+0x19e> + 8001856: 004b lsls r3, r1, #1 + 8001858: 1ac0 subs r0, r0, r3 + 800185a: 4152 adcs r2, r2 + 800185c: 1a41 subs r1, r0, r1 + 800185e: d200 bcs.n 8001862 <__divsi3+0x1a6> + 8001860: 4601 mov r1, r0 + 8001862: 4663 mov r3, ip + 8001864: 4152 adcs r2, r2 + 8001866: 105b asrs r3, r3, #1 + 8001868: 4610 mov r0, r2 + 800186a: d301 bcc.n 8001870 <__divsi3+0x1b4> + 800186c: 4240 negs r0, r0 + 800186e: 2b00 cmp r3, #0 + 8001870: d500 bpl.n 8001874 <__divsi3+0x1b8> + 8001872: 4249 negs r1, r1 + 8001874: 4770 bx lr + 8001876: 4663 mov r3, ip + 8001878: 105b asrs r3, r3, #1 + 800187a: d300 bcc.n 800187e <__divsi3+0x1c2> + 800187c: 4240 negs r0, r0 + 800187e: b501 push {r0, lr} + 8001880: 2000 movs r0, #0 + 8001882: f000 f805 bl 8001890 <__aeabi_idiv0> + 8001886: bd02 pop {r1, pc} + +08001888 <__aeabi_idivmod>: + 8001888: 2900 cmp r1, #0 + 800188a: d0f8 beq.n 800187e <__divsi3+0x1c2> + 800188c: e716 b.n 80016bc <__divsi3> + 800188e: 4770 bx lr + +08001890 <__aeabi_idiv0>: + 8001890: 4770 bx lr + 8001892: 46c0 nop ; (mov r8, r8) + +08001894 <Reset_Handler>: + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + ldr r0, =_estack + 8001894: 480c ldr r0, [pc, #48] ; (80018c8 <LoopForever+0x2>) + mov sp, r0 /* set stack pointer */ + 8001896: 4685 mov sp, r0 + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + 8001898: 2100 movs r1, #0 + b LoopCopyDataInit + 800189a: e003 b.n 80018a4 <LoopCopyDataInit> + +0800189c <CopyDataInit>: + +CopyDataInit: + ldr r3, =_sidata + 800189c: 4b0b ldr r3, [pc, #44] ; (80018cc <LoopForever+0x6>) + ldr r3, [r3, r1] + 800189e: 585b ldr r3, [r3, r1] + str r3, [r0, r1] + 80018a0: 5043 str r3, [r0, r1] + adds r1, r1, #4 + 80018a2: 3104 adds r1, #4 + +080018a4 <LoopCopyDataInit>: + +LoopCopyDataInit: + ldr r0, =_sdata + 80018a4: 480a ldr r0, [pc, #40] ; (80018d0 <LoopForever+0xa>) + ldr r3, =_edata + 80018a6: 4b0b ldr r3, [pc, #44] ; (80018d4 <LoopForever+0xe>) + adds r2, r0, r1 + 80018a8: 1842 adds r2, r0, r1 + cmp r2, r3 + 80018aa: 429a cmp r2, r3 + bcc CopyDataInit + 80018ac: d3f6 bcc.n 800189c <CopyDataInit> + ldr r2, =_sbss + 80018ae: 4a0a ldr r2, [pc, #40] ; (80018d8 <LoopForever+0x12>) + b LoopFillZerobss + 80018b0: e002 b.n 80018b8 <LoopFillZerobss> + +080018b2 <FillZerobss>: +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + 80018b2: 2300 movs r3, #0 + str r3, [r2] + 80018b4: 6013 str r3, [r2, #0] + adds r2, r2, #4 + 80018b6: 3204 adds r2, #4 + +080018b8 <LoopFillZerobss>: + + +LoopFillZerobss: + ldr r3, = _ebss + 80018b8: 4b08 ldr r3, [pc, #32] ; (80018dc <LoopForever+0x16>) + cmp r2, r3 + 80018ba: 429a cmp r2, r3 + bcc FillZerobss + 80018bc: d3f9 bcc.n 80018b2 <FillZerobss> + +/* Call the clock system intitialization function.*/ + bl SystemInit + 80018be: f7ff faad bl 8000e1c <SystemInit> +/* Call static constructors */ +// bl __libc_init_array +/* Call the application's entry point.*/ + bl main + 80018c2: f7fe fcaa bl 800021a <main> + +080018c6 <LoopForever>: + +LoopForever: + b LoopForever + 80018c6: e7fe b.n 80018c6 <LoopForever> + ldr r0, =_estack + 80018c8: 20001000 .word 0x20001000 + ldr r3, =_sidata + 80018cc: 08001904 .word 0x08001904 + ldr r0, =_sdata + 80018d0: 20000000 .word 0x20000000 + ldr r3, =_edata + 80018d4: 20000094 .word 0x20000094 + ldr r2, =_sbss + 80018d8: 20000094 .word 0x20000094 + ldr r3, = _ebss + 80018dc: 200009d4 .word 0x200009d4 + +080018e0 <ADC1_IRQHandler>: + * @retval : None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + 80018e0: e7fe b.n 80018e0 <ADC1_IRQHandler> + 80018e2: 0000 movs r0, r0 + 80018e4: 424f4f46 .word 0x424f4f46 + 80018e8: 000a5241 .word 0x000a5241 + +080018ec <AHBPrescTable>: + ... + 80018f4: 04030201 09080706 ........ + +080018fc <APBPrescTable>: + 80018fc: 00000000 04030201 ........ diff --git a/gm_platform/fw/main.map b/gm_platform/fw/main.map new file mode 100644 index 0000000..ecbce31 --- /dev/null +++ b/gm_platform/fw/main.map @@ -0,0 +1,457 @@ +Archive member included to satisfy reference by file (symbol) + +/usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o) + /tmp/cchCmUnQ.o (__aeabi_uidiv) +/usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o) + /tmp/cczzmF2c.o (__aeabi_idiv) +/usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o) + /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o) (__aeabi_idiv0) + +Allocating common symbols +Common symbol size file + +usart_tx_buf 0x10c /tmp/cc4OHQ7z.o +leds 0x20 /tmp/cchCmUnQ.o +adc_buf 0x800 /tmp/cczzmF2c.o + +Memory Configuration + +Name Origin Length Attributes +FLASH 0x0000000008000000 0x0000000000003c00 xr +CONFIGFLASH 0x0000000008003c00 0x0000000000000400 rw +RAM 0x0000000020000000 0x0000000000001000 xrw +*default* 0x0000000000000000 0xffffffffffffffff + +Linker script and memory map + +LOAD /home/user/resource/STM32CubeF0/Drivers/CMSIS/Lib/GCC/libarm_cortexM0l_math.a +LOAD /tmp/cchCmUnQ.o +LOAD /tmp/cczzmF2c.o +LOAD /tmp/cc4OHQ7z.o +LOAD /tmp/cc0OqFzX.o +LOAD /tmp/ccTaPb5k.o +LOAD /tmp/cc6XVkRI.o +LOAD /tmp/ccvZIDd7.o +LOAD /tmp/ccTEVTRv.o +LOAD /tmp/ccvICuLU.o +LOAD /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a + 0x0000000020001000 _estack = 0x20001000 + +.isr_vector 0x0000000008000000 0xc0 + 0x0000000008000000 . = ALIGN (0x4) + *(.isr_vector) + .isr_vector 0x0000000008000000 0xc0 /tmp/ccTaPb5k.o + 0x0000000008000000 g_pfnVectors + 0x00000000080000c0 . = ALIGN (0x4) + +.text 0x00000000080000c0 0x1844 + 0x00000000080000c0 . = ALIGN (0x4) + *(.text) + .text 0x00000000080000c0 0x454 /tmp/cchCmUnQ.o + 0x0000000008000210 update_leds + 0x000000000800021a main + 0x00000000080003c8 SPI1_IRQHandler + 0x00000000080003f4 TIM16_IRQHandler + 0x00000000080004b0 NMI_Handler + 0x00000000080004bc HardFault_Handler + 0x00000000080004c0 SVC_Handler + 0x00000000080004cc PendSV_Handler + 0x00000000080004d8 SysTick_Handler + .text 0x0000000008000514 0x29c /tmp/cczzmF2c.o + 0x000000000800061c adc_configure_scope_mode + 0x0000000008000792 DMA1_Channel1_IRQHandler + .text 0x00000000080007b0 0x31c /tmp/cc4OHQ7z.o + 0x00000000080008e8 usart_dma_init + 0x00000000080009d4 usart_dma_fifo_push + 0x0000000008000a2c usart_putc + 0x0000000008000a5c DMA1_Channel2_3_IRQHandler + 0x0000000008000a9c usart_send_packet + .text 0x0000000008000acc 0x33a /tmp/cc0OqFzX.o + 0x0000000008000acc cobs_encode + 0x0000000008000b92 cobs_encode_usart + 0x0000000008000c32 cobs_decode + 0x0000000008000d08 cobs_decode_incremental_initialize + 0x0000000008000d24 cobs_decode_incremental + .text 0x0000000008000e06 0x14 /tmp/ccTaPb5k.o + *fill* 0x0000000008000e1a 0x2 + .text 0x0000000008000e1c 0x174 /tmp/cc6XVkRI.o + 0x0000000008000e1c SystemInit + 0x0000000008000ea4 SystemCoreClockUpdate + .text 0x0000000008000f90 0x594 /tmp/ccvZIDd7.o + 0x00000000080011e4 LL_Init1msTick + 0x0000000008001202 LL_mDelay + 0x0000000008001248 LL_SetSystemCoreClock + 0x0000000008001264 LL_PLL_ConfigSystemClock_HSI + 0x00000000080012f0 LL_PLL_ConfigSystemClock_HSE + .text 0x0000000008001524 0x82 /tmp/ccTEVTRv.o + 0x0000000008001524 __sinit + 0x000000000800152e memset + 0x0000000008001568 strlen + 0x0000000008001592 __assert_func + .text 0x00000000080015a6 0x0 /tmp/ccvICuLU.o + *fill* 0x00000000080015a6 0x2 + .text 0x00000000080015a8 0x114 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o) + 0x00000000080015a8 __udivsi3 + 0x00000000080015a8 __aeabi_uidiv + 0x00000000080016b4 __aeabi_uidivmod + .text 0x00000000080016bc 0x1d4 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o) + 0x00000000080016bc __aeabi_idiv + 0x00000000080016bc __divsi3 + 0x0000000008001888 __aeabi_idivmod + .text 0x0000000008001890 0x4 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o) + 0x0000000008001890 __aeabi_ldiv0 + 0x0000000008001890 __aeabi_idiv0 + *(.text.*) + .text.Reset_Handler + 0x0000000008001894 0x4c /tmp/ccTaPb5k.o + 0x0000000008001894 Reset_Handler + .text.Default_Handler + 0x00000000080018e0 0x2 /tmp/ccTaPb5k.o + 0x00000000080018e0 TIM1_CC_IRQHandler + 0x00000000080018e0 I2C1_IRQHandler + 0x00000000080018e0 EXTI2_3_IRQHandler + 0x00000000080018e0 ADC1_IRQHandler + 0x00000000080018e0 TIM17_IRQHandler + 0x00000000080018e0 RTC_IRQHandler + 0x00000000080018e0 TIM3_IRQHandler + 0x00000000080018e0 EXTI4_15_IRQHandler + 0x00000000080018e0 RCC_IRQHandler + 0x00000000080018e0 Default_Handler + 0x00000000080018e0 TIM14_IRQHandler + 0x00000000080018e0 DMA1_Channel4_5_IRQHandler + 0x00000000080018e0 EXTI0_1_IRQHandler + 0x00000000080018e0 WWDG_IRQHandler + 0x00000000080018e0 FLASH_IRQHandler + 0x00000000080018e0 USART1_IRQHandler + 0x00000000080018e0 TIM1_BRK_UP_TRG_COM_IRQHandler + *(.rodata) + *fill* 0x00000000080018e2 0x2 + .rodata 0x00000000080018e4 0x8 /tmp/cchCmUnQ.o + .rodata 0x00000000080018ec 0x18 /tmp/cc6XVkRI.o + 0x00000000080018ec AHBPrescTable + 0x00000000080018fc APBPrescTable + *(.rodata*) + *(.glue_7) + .glue_7 0x0000000008001904 0x0 linker stubs + *(.glue_7t) + .glue_7t 0x0000000008001904 0x0 linker stubs + *(.source_tarball) + *(.init) + *(.fini) + *(.source_tarball) + 0x0000000008001904 . = ALIGN (0x4) + 0x0000000008001904 _etext = . + 0x0000000008001904 _sidata = _etext + +.vfp11_veneer 0x0000000008001904 0x0 + .vfp11_veneer 0x0000000008001904 0x0 linker stubs + +.v4_bx 0x0000000008001904 0x0 + .v4_bx 0x0000000008001904 0x0 linker stubs + +.iplt 0x0000000008001904 0x0 + .iplt 0x0000000008001904 0x0 /tmp/cchCmUnQ.o + +.rel.dyn 0x0000000008001904 0x0 + .rel.iplt 0x0000000008001904 0x0 /tmp/cchCmUnQ.o + +.data 0x0000000020000000 0x94 load address 0x0000000008001904 + 0x0000000020000000 . = ALIGN (0x4) + 0x0000000020000000 _sdata = . + 0x0000000020000000 _data = . + *(.data) + .data 0x0000000020000000 0x0 /tmp/cchCmUnQ.o + .data 0x0000000020000000 0x0 /tmp/cczzmF2c.o + .data 0x0000000020000000 0x0 /tmp/cc4OHQ7z.o + .data 0x0000000020000000 0x0 /tmp/cc0OqFzX.o + .data 0x0000000020000000 0x0 /tmp/ccTaPb5k.o + .data 0x0000000020000000 0x4 /tmp/cc6XVkRI.o + 0x0000000020000000 SystemCoreClock + .data 0x0000000020000004 0x0 /tmp/ccvZIDd7.o + .data 0x0000000020000004 0x0 /tmp/ccTEVTRv.o + .data 0x0000000020000004 0x90 /tmp/ccvICuLU.o + 0x0000000020000004 tim3 + 0x0000000020000008 tim14 + 0x000000002000000c rtc + 0x0000000020000010 wwdg + 0x0000000020000014 iwdg + 0x0000000020000018 i2c1 + 0x000000002000001c pwr + 0x0000000020000020 syscfg + 0x0000000020000024 exti + 0x0000000020000028 adc1 + 0x000000002000002c adc1_common + 0x0000000020000030 adc + 0x0000000020000034 tim1 + 0x0000000020000038 spi1 + 0x000000002000003c usart1 + 0x0000000020000040 tim16 + 0x0000000020000044 tim17 + 0x0000000020000048 dbgmcu + 0x000000002000004c dma1 + 0x0000000020000050 dma1_channel1 + 0x0000000020000054 dma1_channel2 + 0x0000000020000058 dma1_channel3 + 0x000000002000005c dma1_channel4 + 0x0000000020000060 dma1_channel5 + 0x0000000020000064 flash + 0x0000000020000068 ob + 0x000000002000006c rcc + 0x0000000020000070 crc + 0x0000000020000074 gpioa + 0x0000000020000078 gpiob + 0x000000002000007c gpioc + 0x0000000020000080 gpiod + 0x0000000020000084 gpiof + 0x0000000020000088 scb + 0x000000002000008c systick + 0x0000000020000090 nvic + .data 0x0000000020000094 0x0 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o) + .data 0x0000000020000094 0x0 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o) + .data 0x0000000020000094 0x0 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o) + *(.data.*) + *(.RAMtext) + 0x0000000020000094 . = ALIGN (0x4) + 0x0000000020000094 _edata = . + +.igot.plt 0x0000000020000094 0x0 load address 0x0000000008001998 + .igot.plt 0x0000000020000094 0x0 /tmp/cchCmUnQ.o + +.bss 0x0000000020000094 0x940 load address 0x0000000008001998 + 0x0000000020000094 . = ALIGN (0x4) + 0x0000000020000094 _sbss = . + 0x0000000020000094 _bss = . + *(.bss) + .bss 0x0000000020000094 0xc /tmp/cchCmUnQ.o + 0x0000000020000094 sys_time_seconds + .bss 0x00000000200000a0 0x0 /tmp/cczzmF2c.o + .bss 0x00000000200000a0 0x0 /tmp/cc4OHQ7z.o + .bss 0x00000000200000a0 0x0 /tmp/cc0OqFzX.o + .bss 0x00000000200000a0 0x0 /tmp/ccTaPb5k.o + .bss 0x00000000200000a0 0x0 /tmp/cc6XVkRI.o + .bss 0x00000000200000a0 0x0 /tmp/ccvZIDd7.o + .bss 0x00000000200000a0 0x8 /tmp/ccTEVTRv.o + 0x00000000200000a0 __errno + 0x00000000200000a4 _impure_ptr + .bss 0x00000000200000a8 0x0 /tmp/ccvICuLU.o + .bss 0x00000000200000a8 0x0 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o) + .bss 0x00000000200000a8 0x0 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o) + .bss 0x00000000200000a8 0x0 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o) + *(.bss.*) + *(COMMON) + COMMON 0x00000000200000a8 0x20 /tmp/cchCmUnQ.o + 0x00000000200000a8 leds + COMMON 0x00000000200000c8 0x800 /tmp/cczzmF2c.o + 0x00000000200000c8 adc_buf + COMMON 0x00000000200008c8 0x10c /tmp/cc4OHQ7z.o + 0x00000000200008c8 usart_tx_buf + 0x00000000200009d4 . = ALIGN (0x4) + 0x00000000200009d4 _ebss = . + [!provide] PROVIDE (end = _ebss) + [!provide] PROVIDE (_end = _ebss) + 0x00000000200009d4 __exidx_start = . + 0x00000000200009d4 __exidx_end = . + +.stab + *(.stab) + +.stabstr + *(.stabstr) + +.stab.excl + *(.stab.excl) + +.stab.exclstr + *(.stab.exclstr) + +.stab.index + *(.stab.index) + +.stab.indexstr + *(.stab.indexstr) + +.comment 0x0000000000000000 0x21 + *(.comment) + .comment 0x0000000000000000 0x21 /tmp/cchCmUnQ.o + 0x22 (size before relaxing) + .comment 0x0000000000000021 0x22 /tmp/cczzmF2c.o + .comment 0x0000000000000021 0x22 /tmp/cc4OHQ7z.o + .comment 0x0000000000000021 0x22 /tmp/cc0OqFzX.o + .comment 0x0000000000000021 0x22 /tmp/cc6XVkRI.o + .comment 0x0000000000000021 0x22 /tmp/ccvZIDd7.o + .comment 0x0000000000000021 0x22 /tmp/ccTEVTRv.o + .comment 0x0000000000000021 0x22 /tmp/ccvICuLU.o + +.ARM.attributes + 0x0000000000000000 0x2f + .ARM.attributes + 0x0000000000000000 0x2b /tmp/cchCmUnQ.o + .ARM.attributes + 0x000000000000002b 0x2b /tmp/cczzmF2c.o + .ARM.attributes + 0x0000000000000056 0x2b /tmp/cc4OHQ7z.o + .ARM.attributes + 0x0000000000000081 0x2b /tmp/cc0OqFzX.o + .ARM.attributes + 0x00000000000000ac 0x21 /tmp/ccTaPb5k.o + .ARM.attributes + 0x00000000000000cd 0x2b /tmp/cc6XVkRI.o + .ARM.attributes + 0x00000000000000f8 0x2b /tmp/ccvZIDd7.o + .ARM.attributes + 0x0000000000000123 0x2b /tmp/ccTEVTRv.o + .ARM.attributes + 0x000000000000014e 0x31 /tmp/ccvICuLU.o + .ARM.attributes + 0x000000000000017f 0x1e /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o) + .ARM.attributes + 0x000000000000019d 0x1e /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o) + .ARM.attributes + 0x00000000000001bb 0x1e /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o) + +.debug + *(.debug) + +.line + *(.line) + +.debug_srcinfo + *(.debug_srcinfo) + +.debug_sfnames + *(.debug_sfnames) + +.debug_aranges 0x0000000000000000 0x180 + *(.debug_aranges) + .debug_aranges + 0x0000000000000000 0x20 /tmp/cchCmUnQ.o + .debug_aranges + 0x0000000000000020 0x20 /tmp/cczzmF2c.o + .debug_aranges + 0x0000000000000040 0x20 /tmp/cc4OHQ7z.o + .debug_aranges + 0x0000000000000060 0x20 /tmp/cc0OqFzX.o + .debug_aranges + 0x0000000000000080 0x28 /tmp/ccTaPb5k.o + .debug_aranges + 0x00000000000000a8 0x20 /tmp/cc6XVkRI.o + .debug_aranges + 0x00000000000000c8 0x20 /tmp/ccvZIDd7.o + .debug_aranges + 0x00000000000000e8 0x20 /tmp/ccTEVTRv.o + .debug_aranges + 0x0000000000000108 0x18 /tmp/ccvICuLU.o + .debug_aranges + 0x0000000000000120 0x20 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o) + .debug_aranges + 0x0000000000000140 0x20 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o) + .debug_aranges + 0x0000000000000160 0x20 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o) + +.debug_pubnames + *(.debug_pubnames) + +.debug_info 0x0000000000000000 0x5d8a + *(.debug_info .gnu.linkonce.wi.*) + .debug_info 0x0000000000000000 0x136b /tmp/cchCmUnQ.o + .debug_info 0x000000000000136b 0x105f /tmp/cczzmF2c.o + .debug_info 0x00000000000023ca 0x1019 /tmp/cc4OHQ7z.o + .debug_info 0x00000000000033e3 0xcb1 /tmp/cc0OqFzX.o + .debug_info 0x0000000000004094 0x22 /tmp/ccTaPb5k.o + .debug_info 0x00000000000040b6 0x263 /tmp/cc6XVkRI.o + .debug_info 0x0000000000004319 0x795 /tmp/ccvZIDd7.o + .debug_info 0x0000000000004aae 0x1e9 /tmp/ccTEVTRv.o + .debug_info 0x0000000000004c97 0x1081 /tmp/ccvICuLU.o + .debug_info 0x0000000000005d18 0x26 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o) + .debug_info 0x0000000000005d3e 0x26 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o) + .debug_info 0x0000000000005d64 0x26 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o) + +.debug_abbrev 0x0000000000000000 0x1204 + *(.debug_abbrev) + .debug_abbrev 0x0000000000000000 0x357 /tmp/cchCmUnQ.o + .debug_abbrev 0x0000000000000357 0x320 /tmp/cczzmF2c.o + .debug_abbrev 0x0000000000000677 0x319 /tmp/cc4OHQ7z.o + .debug_abbrev 0x0000000000000990 0x287 /tmp/cc0OqFzX.o + .debug_abbrev 0x0000000000000c17 0x12 /tmp/ccTaPb5k.o + .debug_abbrev 0x0000000000000c29 0x113 /tmp/cc6XVkRI.o + .debug_abbrev 0x0000000000000d3c 0x23c /tmp/ccvZIDd7.o + .debug_abbrev 0x0000000000000f78 0x117 /tmp/ccTEVTRv.o + .debug_abbrev 0x000000000000108f 0x139 /tmp/ccvICuLU.o + .debug_abbrev 0x00000000000011c8 0x14 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o) + .debug_abbrev 0x00000000000011dc 0x14 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o) + .debug_abbrev 0x00000000000011f0 0x14 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o) + +.debug_line 0x0000000000000000 0x17b1 + *(.debug_line) + .debug_line 0x0000000000000000 0x3ec /tmp/cchCmUnQ.o + .debug_line 0x00000000000003ec 0x33d /tmp/cczzmF2c.o + .debug_line 0x0000000000000729 0x36e /tmp/cc4OHQ7z.o + .debug_line 0x0000000000000a97 0x2f9 /tmp/cc0OqFzX.o + .debug_line 0x0000000000000d90 0x77 /tmp/ccTaPb5k.o + .debug_line 0x0000000000000e07 0x1ab /tmp/cc6XVkRI.o + .debug_line 0x0000000000000fb2 0x466 /tmp/ccvZIDd7.o + .debug_line 0x0000000000001418 0xf4 /tmp/ccTEVTRv.o + .debug_line 0x000000000000150c 0x148 /tmp/ccvICuLU.o + .debug_line 0x0000000000001654 0x76 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o) + .debug_line 0x00000000000016ca 0x7d /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o) + .debug_line 0x0000000000001747 0x6a /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o) + +.debug_frame 0x0000000000000000 0x848 + *(.debug_frame) + .debug_frame 0x0000000000000000 0x168 /tmp/cchCmUnQ.o + .debug_frame 0x0000000000000168 0xe8 /tmp/cczzmF2c.o + .debug_frame 0x0000000000000250 0x128 /tmp/cc4OHQ7z.o + .debug_frame 0x0000000000000378 0xb0 /tmp/cc0OqFzX.o + .debug_frame 0x0000000000000428 0x4c /tmp/cc6XVkRI.o + .debug_frame 0x0000000000000474 0x308 /tmp/ccvZIDd7.o + .debug_frame 0x000000000000077c 0x8c /tmp/ccTEVTRv.o + .debug_frame 0x0000000000000808 0x20 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o) + .debug_frame 0x0000000000000828 0x20 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o) + +.debug_str 0x0000000000000000 0x12b2 + *(.debug_str) + .debug_str 0x0000000000000000 0x965 /tmp/cchCmUnQ.o + 0xa11 (size before relaxing) + .debug_str 0x0000000000000965 0xdf /tmp/cczzmF2c.o + 0x8fc (size before relaxing) + .debug_str 0x0000000000000a44 0xa7 /tmp/cc4OHQ7z.o + 0x904 (size before relaxing) + .debug_str 0x0000000000000aeb 0xa2 /tmp/cc0OqFzX.o + 0x658 (size before relaxing) + .debug_str 0x0000000000000b8d 0x22 /tmp/ccTaPb5k.o + 0x57 (size before relaxing) + .debug_str 0x0000000000000baf 0x53 /tmp/cc6XVkRI.o + 0x219 (size before relaxing) + .debug_str 0x0000000000000c02 0x3ae /tmp/ccvZIDd7.o + 0x5bf (size before relaxing) + .debug_str 0x0000000000000fb0 0x39 /tmp/ccTEVTRv.o + 0x1b7 (size before relaxing) + .debug_str 0x0000000000000fe9 0x227 /tmp/ccvICuLU.o + 0x5ca (size before relaxing) + .debug_str 0x0000000000001210 0xa2 /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_udivsi3.o) + 0xae (size before relaxing) + .debug_str 0x00000000000012b2 0xae /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_divsi3.o) + .debug_str 0x00000000000012b2 0xae /usr/lib/gcc/arm-none-eabi/9.2.0/thumb/v6-m/nofp/libgcc.a(_dvmd_tls.o) + +.debug_loc + *(.debug_loc) + +.debug_macinfo + *(.debug_macinfo) + +.debug_weaknames + *(.debug_weaknames) + +.debug_funcnames + *(.debug_funcnames) + +.debug_typenames + *(.debug_typenames) + +.debug_varnames + *(.debug_varnames) +OUTPUT(main.elf elf32-littlearm) + +.debug_ranges 0x0000000000000000 0x38 + .debug_ranges 0x0000000000000000 0x18 /tmp/cc0OqFzX.o + .debug_ranges 0x0000000000000018 0x20 /tmp/ccTaPb5k.o diff --git a/gm_platform/fw/openocd.cfg b/gm_platform/fw/openocd.cfg new file mode 100644 index 0000000..ce164b7 --- /dev/null +++ b/gm_platform/fw/openocd.cfg @@ -0,0 +1,17 @@ +telnet_port 4445 +gdb_port 3334 +tcl_port 6667 + +source [find interface/stlink-v2.cfg] +#interface jlink +#interface stlink-v2 +#adapter_khz 10000 +#transport select swd + +#source /usr/share/openocd/scripts/target/stm32f0x.cfg +source [find target/stm32f0x_stlink.cfg] + +init +arm semihosting enable + +#flash bank sysflash.alias stm32f0x 0x00000000 0 0 0 $_TARGETNAME diff --git a/gm_platform/fw/packet_interface.c b/gm_platform/fw/packet_interface.c new file mode 100644 index 0000000..099993b --- /dev/null +++ b/gm_platform/fw/packet_interface.c @@ -0,0 +1,46 @@ + +#include "packet_interface.h" +#include "cobs.h" + +void usart2_isr(void) { + TRACING_SET(TR_HOST_IF_USART_IRQ); + static struct cobs_decode_state host_cobs_state = {0}; + if (USART2_SR & USART_SR_ORE) { /* Overrun handling */ + LOG_PRINTF("USART2 data register overrun\n"); + /* Clear interrupt flag */ + (void)USART2_DR; /* FIXME make sure this read is not optimized out */ + host_packet_length = -1; + TRACING_CLEAR(TR_HOST_IF_USART_IRQ); + return; + } + + uint8_t data = USART2_DR; /* This automatically acknowledges the IRQ */ + + if (host_packet_length) { + LOG_PRINTF("USART2 COBS buffer overrun\n"); + host_packet_length = -1; + TRACING_CLEAR(TR_HOST_IF_USART_IRQ); + return; + } + + ssize_t rv = cobs_decode_incremental(&host_cobs_state, (char *)host_packet_buf, sizeof(host_packet_buf), data); + if (rv == -2) { + LOG_PRINTF("Host interface COBS packet too large\n"); + host_packet_length = -1; + } else if (rv == -3) { + LOG_PRINTF("Got double null byte from host\n"); + } else if (rv < 0) { + LOG_PRINTF("Host interface COBS framing error\n"); + host_packet_length = -1; + } else if (rv > 0) { + host_packet_length = rv; + } /* else just return and wait for next byte */ + TRACING_CLEAR(TR_HOST_IF_USART_IRQ); +} + +void send_packet(struct dma_usart_file *f, const uint8_t *data, size_t len) { + /* ignore return value as putf is blocking and always succeeds */ + (void)cobs_encode_incremental(f, putf, (char *)data, len); + flush(f); +} + diff --git a/gm_platform/fw/packet_interface.h b/gm_platform/fw/packet_interface.h new file mode 100644 index 0000000..dbace62 --- /dev/null +++ b/gm_platform/fw/packet_interface.h @@ -0,0 +1,6 @@ +#ifndef __PACKET_INTERFACE_H__ +#define __PACKET_INTERFACE_H__ + +void send_packet(struct dma_usart_file *f, const uint8_t *data, size_t len); + +#endif diff --git a/gm_platform/fw/scope.gdb b/gm_platform/fw/scope.gdb new file mode 100644 index 0000000..01366fa --- /dev/null +++ b/gm_platform/fw/scope.gdb @@ -0,0 +1,12 @@ +target remote 192.168.178.103:3334 +set pagination off +file main.elf +load + +break gdb_dump +command 1 + dump binary value /tmp/scope_dump.bin adc_buf + continue +end + +continue diff --git a/gm_platform/fw/serial.c b/gm_platform/fw/serial.c new file mode 100644 index 0000000..ae639c0 --- /dev/null +++ b/gm_platform/fw/serial.c @@ -0,0 +1,139 @@ +/*
+ * This file is part of the libusbhost library
+ * hosted at http://github.com/libusbhost/libusbhost
+ *
+ * Copyright (C) 2015 Amir Hammad <amir.hammad@hotmail.com>
+ *
+ *
+ * libusbhost is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#include "global.h"
+#include "serial.h"
+#include "cobs.h"
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+volatile struct dma_tx_buf usart_tx_buf;
+
+static void usart_schedule_dma();
+
+void usart_dma_init() {
+ usart_tx_buf.xfr_start = -1,
+ usart_tx_buf.xfr_end = 0,
+ usart_tx_buf.wr_pos = 0,
+
+ /* Configure DMA 1 Channel 2 to handle uart transmission */
+ DMA1_Channel2->CPAR = (unsigned int)&(USART1->TDR);
+ DMA1_Channel2->CCR = (0<<DMA_CCR_PL_Pos)
+ | DMA_CCR_DIR
+ | (0<<DMA_CCR_MSIZE_Pos) /* 8 bit */
+ | (0<<DMA_CCR_PSIZE_Pos) /* 8 bit */
+ | DMA_CCR_MINC
+ | DMA_CCR_TCIE; /* Enable transfer complete interrupt. */
+
+ /* triggered on transfer completion. We use this to process the ADC data */
+ NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
+ NVIC_SetPriority(DMA1_Channel2_3_IRQn, 1<<5);
+
+ USART1->CR1 = /* 8-bit -> M1, M0 clear */
+ /* OVER8 clear. Use default 16x oversampling */
+ /* CMIF clear */
+ USART_CR1_MME
+ /* WAKE clear */
+ /* PCE, PS clear */
+ | USART_CR1_RXNEIE /* Enable receive interrupt */
+ /* other interrupts clear */
+ | USART_CR1_TE
+ | USART_CR1_RE;
+ /* Set divider for 1MBd @48MHz system clock. */
+ USART1->BRR = 48;
+
+ USART1->CR2 = USART_CR2_TXINV | USART_CR2_RXINV;
+
+ USART1->CR3 |= USART_CR3_DMAT; /* TX DMA enable */
+
+ /* Enable receive interrupt */
+ //NVIC_EnableIRQ(USART1_IRQn);
+ //NVIC_SetPriority(USART1_IRQn, 1);
+
+ /* And... go! */
+ USART1->CR1 |= USART_CR1_UE;
+}
+
+void usart_schedule_dma() {
+ /* This function is only called when the DMA channel is disabled. This means we don't have to guard it in IRQ
+ * disables. */
+ volatile struct dma_tx_buf *buf = &usart_tx_buf;
+
+ size_t xfr_len, xfr_start = buf->xfr_end;
+ if (buf->wr_pos > xfr_start) /* no wraparound */
+ xfr_len = buf->wr_pos - xfr_start;
+ else /* wraparound */
+ xfr_len = sizeof(buf->data) - xfr_start; /* schedule transfer until end of buffer */
+
+ buf->xfr_start = xfr_start;
+ buf->xfr_end = (xfr_start + xfr_len) % sizeof(buf->data); /* handle wraparound */
+
+ /* initiate transmission of new buffer */
+ DMA1_Channel2->CMAR = (uint32_t)(buf->data + xfr_start);
+ DMA1_Channel2->CNDTR = xfr_len;
+ DMA1_Channel2->CCR |= DMA_CCR_EN;
+}
+
+int usart_dma_fifo_push(volatile struct dma_tx_buf *buf, char c) {
+ /* This function must be guarded by IRQ disable since the IRQ may schedule a new transfer and charge pos/start. */
+ NVIC_DisableIRQ(DMA1_Channel2_3_IRQn);
+
+ if (buf->wr_pos == buf->xfr_start) {
+ NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
+ return -EBUSY;
+ }
+
+ buf->data[buf->wr_pos] = c;
+ buf->wr_pos = (buf->wr_pos + 1) % sizeof(buf->data);
+
+ NVIC_EnableIRQ(DMA1_Channel2_3_IRQn);
+ return 0;
+}
+
+void usart_putc(char c) {
+ /* push char to fifo, busy-loop if stalled to wait for USART to empty fifo via DMA */
+ while (usart_dma_fifo_push(&usart_tx_buf, c) == -EBUSY) {
+ /* idle */
+ }
+}
+
+void DMA1_Channel2_3_IRQHandler(void) {
+ /* Transfer complete */
+ DMA1->IFCR |= DMA_IFCR_CTCIF2;
+
+ DMA1_Channel2->CCR &= ~DMA_CCR_EN;
+ if (usart_tx_buf.wr_pos != usart_tx_buf.xfr_end) /* buffer not empty */
+ usart_schedule_dma();
+}
+
+void usart_send_packet(const uint8_t *data, size_t len) {
+ /* ignore return value as putf is blocking and always succeeds */
+ (void)cobs_encode_usart((char *)data, len);
+
+ /* If the DMA stream is idle right now, schedule a transfer */
+ if (!(DMA1_Channel2->CCR & DMA_CCR_EN))
+ usart_schedule_dma();
+}
+
diff --git a/gm_platform/fw/serial.h b/gm_platform/fw/serial.h new file mode 100644 index 0000000..55eac9e --- /dev/null +++ b/gm_platform/fw/serial.h @@ -0,0 +1,44 @@ +/*
+ * This file is part of the libusbhost library
+ * hosted at http://github.com/libusbhost/libusbhost
+ *
+ * Copyright (C) 2015 Amir Hammad <amir.hammad@hotmail.com>
+ *
+ *
+ * libusbhost is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef __SERIAL_H__
+#define __SERIAL_H__
+
+#include <stdint.h>
+#include <stdarg.h>
+#include <errno.h>
+
+struct dma_tx_buf {
+ size_t xfr_start; /* Start index of running DMA transfer */
+ size_t xfr_end; /* End index of running DMA transfer plus one */
+ size_t wr_pos; /* Next index to be written */
+ uint8_t data[256];
+};
+
+extern volatile struct dma_tx_buf usart_tx_buf;
+
+void usart_dma_init(void);
+int usart_dma_fifo_push(volatile struct dma_tx_buf *buf, char c);
+void usart_putc(char c);
+void usart_send_packet(const uint8_t *data, size_t len);
+
+#endif // __SERIAL_H__
diff --git a/gm_platform/fw/startup_stm32f030x6.s b/gm_platform/fw/startup_stm32f030x6.s new file mode 100644 index 0000000..2f0eb42 --- /dev/null +++ b/gm_platform/fw/startup_stm32f030x6.s @@ -0,0 +1,273 @@ +/**
+ ******************************************************************************
+ * @file startup_stm32f030x6.s
+ * copied from: STM32Cube/Drivers/CMSIS/Device/ST/STM32F0xx/Source/Templates/gcc
+ * @author MCD Application Team
+ * @version V2.3.1
+ * @date 04-November-2016
+ * @brief STM32F030x4/STM32F030x6 devices vector table for Atollic TrueSTUDIO toolchain.
+ * This module performs:
+ * - Set the initial SP
+ * - Set the initial PC == Reset_Handler,
+ * - Set the vector table entries with the exceptions ISR address
+ * - Branches to main in the C library (which eventually
+ * calls main()).
+ * After Reset the Cortex-M0 processor is in Thread mode,
+ * priority is Privileged, and the Stack is set to Main.
+ ******************************************************************************
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+ .syntax unified
+ .cpu cortex-m0
+ .fpu softvfp
+ .thumb
+
+.global g_pfnVectors
+.global Default_Handler
+
+/* start address for the initialization values of the .data section.
+defined in linker script */
+.word _sidata
+/* start address for the .data section. defined in linker script */
+.word _sdata
+/* end address for the .data section. defined in linker script */
+.word _edata
+/* start address for the .bss section. defined in linker script */
+.word _sbss
+/* end address for the .bss section. defined in linker script */
+.word _ebss
+
+ .section .text.Reset_Handler
+ .weak Reset_Handler
+ .type Reset_Handler, %function
+Reset_Handler:
+ ldr r0, =_estack
+ mov sp, r0 /* set stack pointer */
+
+/* Copy the data segment initializers from flash to SRAM */
+ movs r1, #0
+ b LoopCopyDataInit
+
+CopyDataInit:
+ ldr r3, =_sidata
+ ldr r3, [r3, r1]
+ str r3, [r0, r1]
+ adds r1, r1, #4
+
+LoopCopyDataInit:
+ ldr r0, =_sdata
+ ldr r3, =_edata
+ adds r2, r0, r1
+ cmp r2, r3
+ bcc CopyDataInit
+ ldr r2, =_sbss
+ b LoopFillZerobss
+/* Zero fill the bss segment. */
+FillZerobss:
+ movs r3, #0
+ str r3, [r2]
+ adds r2, r2, #4
+
+
+LoopFillZerobss:
+ ldr r3, = _ebss
+ cmp r2, r3
+ bcc FillZerobss
+
+/* Call the clock system intitialization function.*/
+ bl SystemInit
+/* Call static constructors */
+// bl __libc_init_array
+/* Call the application's entry point.*/
+ bl main
+
+LoopForever:
+ b LoopForever
+
+
+.size Reset_Handler, .-Reset_Handler
+
+/**
+ * @brief This is the code that gets called when the processor receives an
+ * unexpected interrupt. This simply enters an infinite loop, preserving
+ * the system state for examination by a debugger.
+ *
+ * @param None
+ * @retval : None
+*/
+ .section .text.Default_Handler,"ax",%progbits
+Default_Handler:
+Infinite_Loop:
+ b Infinite_Loop
+ .size Default_Handler, .-Default_Handler
+/******************************************************************************
+*
+* The minimal vector table for a Cortex M0. Note that the proper constructs
+* must be placed on this to ensure that it ends up at physical address
+* 0x0000.0000.
+*
+******************************************************************************/
+ .section .isr_vector,"a",%progbits
+ .type g_pfnVectors, %object
+ .size g_pfnVectors, .-g_pfnVectors
+
+
+g_pfnVectors:
+ .word _estack
+ .word Reset_Handler
+ .word NMI_Handler
+ .word HardFault_Handler
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word 0
+ .word SVC_Handler
+ .word 0
+ .word 0
+ .word PendSV_Handler
+ .word SysTick_Handler
+ .word WWDG_IRQHandler /* Window WatchDog */
+ .word 0 /* Reserved */
+ .word RTC_IRQHandler /* RTC through the EXTI line */
+ .word FLASH_IRQHandler /* FLASH */
+ .word RCC_IRQHandler /* RCC */
+ .word EXTI0_1_IRQHandler /* EXTI Line 0 and 1 */
+ .word EXTI2_3_IRQHandler /* EXTI Line 2 and 3 */
+ .word EXTI4_15_IRQHandler /* EXTI Line 4 to 15 */
+ .word 0 /* Reserved */
+ .word DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */
+ .word DMA1_Channel2_3_IRQHandler /* DMA1 Channel 2 and Channel 3 */
+ .word DMA1_Channel4_5_IRQHandler /* DMA1 Channel 4 and Channel 5 */
+ .word ADC1_IRQHandler /* ADC1 */
+ .word TIM1_BRK_UP_TRG_COM_IRQHandler /* TIM1 Break, Update, Trigger and Commutation */
+ .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */
+ .word 0 /* Reserved */
+ .word TIM3_IRQHandler /* TIM3 */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word TIM14_IRQHandler /* TIM14 */
+ .word 0 /* Reserved */
+ .word TIM16_IRQHandler /* TIM16 */
+ .word TIM17_IRQHandler /* TIM17 */
+ .word I2C1_IRQHandler /* I2C1 */
+ .word 0 /* Reserved */
+ .word SPI1_IRQHandler /* SPI1 */
+ .word 0 /* Reserved */
+ .word USART1_IRQHandler /* USART1 */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+ .word 0 /* Reserved */
+
+/*******************************************************************************
+*
+* Provide weak aliases for each Exception handler to the Default_Handler.
+* As they are weak aliases, any function with the same name will override
+* this definition.
+*
+*******************************************************************************/
+
+ .weak NMI_Handler
+ .thumb_set NMI_Handler,Default_Handler
+
+ .weak HardFault_Handler
+ .thumb_set HardFault_Handler,Default_Handler
+
+ .weak SVC_Handler
+ .thumb_set SVC_Handler,Default_Handler
+
+ .weak PendSV_Handler
+ .thumb_set PendSV_Handler,Default_Handler
+
+ .weak SysTick_Handler
+ .thumb_set SysTick_Handler,Default_Handler
+
+ .weak WWDG_IRQHandler
+ .thumb_set WWDG_IRQHandler,Default_Handler
+
+ .weak RTC_IRQHandler
+ .thumb_set RTC_IRQHandler,Default_Handler
+
+ .weak FLASH_IRQHandler
+ .thumb_set FLASH_IRQHandler,Default_Handler
+
+ .weak RCC_IRQHandler
+ .thumb_set RCC_IRQHandler,Default_Handler
+
+ .weak EXTI0_1_IRQHandler
+ .thumb_set EXTI0_1_IRQHandler,Default_Handler
+
+ .weak EXTI2_3_IRQHandler
+ .thumb_set EXTI2_3_IRQHandler,Default_Handler
+
+ .weak EXTI4_15_IRQHandler
+ .thumb_set EXTI4_15_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel1_IRQHandler
+ .thumb_set DMA1_Channel1_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel2_3_IRQHandler
+ .thumb_set DMA1_Channel2_3_IRQHandler,Default_Handler
+
+ .weak DMA1_Channel4_5_IRQHandler
+ .thumb_set DMA1_Channel4_5_IRQHandler,Default_Handler
+
+ .weak ADC1_IRQHandler
+ .thumb_set ADC1_IRQHandler,Default_Handler
+
+ .weak TIM1_BRK_UP_TRG_COM_IRQHandler
+ .thumb_set TIM1_BRK_UP_TRG_COM_IRQHandler,Default_Handler
+
+ .weak TIM1_CC_IRQHandler
+ .thumb_set TIM1_CC_IRQHandler,Default_Handler
+
+ .weak TIM3_IRQHandler
+ .thumb_set TIM3_IRQHandler,Default_Handler
+
+ .weak TIM14_IRQHandler
+ .thumb_set TIM14_IRQHandler,Default_Handler
+
+ .weak TIM16_IRQHandler
+ .thumb_set TIM16_IRQHandler,Default_Handler
+
+ .weak TIM17_IRQHandler
+ .thumb_set TIM17_IRQHandler,Default_Handler
+
+ .weak I2C1_IRQHandler
+ .thumb_set I2C1_IRQHandler,Default_Handler
+
+ .weak SPI1_IRQHandler
+ .thumb_set SPI1_IRQHandler,Default_Handler
+
+ .weak USART1_IRQHandler
+ .thumb_set USART1_IRQHandler,Default_Handler
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/gm_platform/fw/stm32_flash.ld b/gm_platform/fw/stm32_flash.ld new file mode 100644 index 0000000..cba7577 --- /dev/null +++ b/gm_platform/fw/stm32_flash.ld @@ -0,0 +1,136 @@ +
+ENTRY(Reset_Handler)
+
+MEMORY {
+ FLASH (rx): ORIGIN = 0x08000000, LENGTH = 0x3C00
+ CONFIGFLASH (rw): ORIGIN = 0x08003C00, LENGTH = 0x400
+ RAM (xrw): ORIGIN = 0x20000000, LENGTH = 4K
+}
+
+/* highest address of the user mode stack */
+_estack = 0x20001000;
+
+SECTIONS {
+ /* for Cortex devices, the beginning of the startup code is stored in the .isr_vector section, which goes to FLASH */
+ .isr_vector : {
+ . = ALIGN(4);
+ KEEP(*(.isr_vector)) /* Startup code */
+ . = ALIGN(4);
+ } >FLASH
+
+ /* the program code is stored in the .text section, which goes to Flash */
+ .text : {
+ . = ALIGN(4);
+
+ *(.text) /* normal code */
+ *(.text.*) /* -ffunction-sections code */
+ *(.rodata) /* read-only data (constants) */
+ *(.rodata*) /* -fdata-sections read only data */
+ *(.glue_7) /* TBD - needed ? */
+ *(.glue_7t) /* TBD - needed ? */
+
+ *(.source_tarball)
+
+ /* Necessary KEEP sections (see http://sourceware.org/ml/newlib/2005/msg00255.html) */
+ KEEP (*(.init))
+ KEEP (*(.fini))
+ KEEP (*(.source_tarball))
+
+ . = ALIGN(4);
+ _etext = .;
+ /* This is used by the startup in order to initialize the .data section */
+ _sidata = _etext;
+ } >FLASH
+
+ /*
+ .configflash : {
+ . = ALIGN(0x400);
+ *(.configdata)
+ _econfig = .;
+ } >FLASH
+ */
+
+ /* This is the initialized data section
+ The program executes knowing that the data is in the RAM
+ but the loader puts the initial values in the FLASH (inidata).
+ It is one task of the startup to copy the initial values from FLASH to RAM. */
+ .data : AT ( _sidata ) {
+ . = ALIGN(4);
+ /* This is used by the startup in order to initialize the .data secion */
+ _sdata = . ;
+ _data = . ;
+
+ *(.data)
+ *(.data.*)
+ *(.RAMtext)
+
+ . = ALIGN(4);
+ /* This is used by the startup in order to initialize the .data secion */
+ _edata = . ;
+ } >RAM
+
+ /* This is the uninitialized data section */
+ .bss : {
+ . = ALIGN(4);
+ /* This is used by the startup in order to initialize the .bss secion */
+ _sbss = .;
+ _bss = .;
+
+ *(.bss)
+ *(.bss.*) /* patched by elias - allows the use of -fdata-sections */
+ *(COMMON)
+
+ . = ALIGN(4);
+ /* This is used by the startup in order to initialize the .bss secion */
+ _ebss = . ;
+ } >RAM
+
+ PROVIDE ( end = _ebss);
+ PROVIDE (_end = _ebss);
+
+ __exidx_start = .;
+ __exidx_end = .;
+
+ /* after that it's only debugging information. */
+
+ /* remove the debugging information from the standard libraries */
+/* /DISCARD/ : {
+ libc.a ( * )
+ libm.a ( * )
+ libgcc.a ( * )
+ }*/
+
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+}
diff --git a/gm_platform/fw/system_stm32f0xx.c b/gm_platform/fw/system_stm32f0xx.c new file mode 100644 index 0000000..a43c3d6 --- /dev/null +++ b/gm_platform/fw/system_stm32f0xx.c @@ -0,0 +1,336 @@ +/**
+ ******************************************************************************
+ * @file system_stm32f0xx.c
+ * copied from: STM32Cube/Drivers/CMSIS/Device/ST/STM32F0xx/Source/Templates
+ * @author MCD Application Team
+ * @version V2.3.1
+ * @date 04-November-2016
+ * @brief CMSIS Cortex-M0 Device Peripheral Access Layer System Source File.
+ *
+ * 1. This file provides two functions and one global variable to be called from
+ * user application:
+ * - SystemInit(): This function is called at startup just after reset and
+ * before branch to main program. This call is made inside
+ * the "startup_stm32f0xx.s" file.
+ *
+ * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used
+ * by the user application to setup the SysTick
+ * timer or configure other parameters.
+ *
+ * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must
+ * be called whenever the core clock is changed
+ * during program execution.
+ *
+ * 2. After each device reset the HSI (8 MHz) is used as system clock source.
+ * Then SystemInit() function is called, in "startup_stm32f0xx.s" file, to
+ * configure the system clock before to branch to main program.
+ *
+ * 3. This file configures the system clock as follows:
+ *=============================================================================
+ * Supported STM32F0xx device
+ *-----------------------------------------------------------------------------
+ * System Clock source | HSI
+ *-----------------------------------------------------------------------------
+ * SYSCLK(Hz) | 8000000
+ *-----------------------------------------------------------------------------
+ * HCLK(Hz) | 8000000
+ *-----------------------------------------------------------------------------
+ * AHB Prescaler | 1
+ *-----------------------------------------------------------------------------
+ * APB1 Prescaler | 1
+ *-----------------------------------------------------------------------------
+ *=============================================================================
+ ******************************************************************************
+ * @attention
+ *
+ * <h2><center>© COPYRIGHT(c) 2016 STMicroelectronics</center></h2>
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ ******************************************************************************
+ */
+
+/** @addtogroup CMSIS
+ * @{
+ */
+
+/** @addtogroup stm32f0xx_system
+ * @{
+ */
+
+/** @addtogroup STM32F0xx_System_Private_Includes
+ * @{
+ */
+
+#include "stm32f0xx.h"
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F0xx_System_Private_TypesDefinitions
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F0xx_System_Private_Defines
+ * @{
+ */
+#if !defined (HSE_VALUE)
+ #define HSE_VALUE ((uint32_t)8000000) /*!< Default value of the External oscillator in Hz.
+ This value can be provided and adapted by the user application. */
+#endif /* HSE_VALUE */
+
+#if !defined (HSI_VALUE)
+ #define HSI_VALUE ((uint32_t)8000000) /*!< Default value of the Internal oscillator in Hz.
+ This value can be provided and adapted by the user application. */
+#endif /* HSI_VALUE */
+
+#if !defined (HSI48_VALUE)
+#define HSI48_VALUE ((uint32_t)48000000) /*!< Default value of the HSI48 Internal oscillator in Hz.
+ This value can be provided and adapted by the user application. */
+#endif /* HSI48_VALUE */
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F0xx_System_Private_Macros
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F0xx_System_Private_Variables
+ * @{
+ */
+ /* This variable is updated in three ways:
+ 1) by calling CMSIS function SystemCoreClockUpdate()
+ 2) by calling HAL API function HAL_RCC_GetHCLKFreq()
+ 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency
+ Note: If you use this function to configure the system clock there is no need to
+ call the 2 first functions listed above, since SystemCoreClock variable is
+ updated automatically.
+ */
+uint32_t SystemCoreClock = 8000000;
+
+const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
+const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4};
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F0xx_System_Private_FunctionPrototypes
+ * @{
+ */
+
+/**
+ * @}
+ */
+
+/** @addtogroup STM32F0xx_System_Private_Functions
+ * @{
+ */
+
+/**
+ * @brief Setup the microcontroller system.
+ * Initialize the default HSI clock source, vector table location and the PLL configuration is reset.
+ * @param None
+ * @retval None
+ */
+void SystemInit(void)
+{
+ /* Reset the RCC clock configuration to the default reset state ------------*/
+ /* Set HSION bit */
+ RCC->CR |= (uint32_t)0x00000001U;
+
+#if defined (STM32F051x8) || defined (STM32F058x8)
+ /* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE and MCOSEL[2:0] bits */
+ RCC->CFGR &= (uint32_t)0xF8FFB80CU;
+#else
+ /* Reset SW[1:0], HPRE[3:0], PPRE[2:0], ADCPRE, MCOSEL[2:0], MCOPRE[2:0] and PLLNODIV bits */
+ RCC->CFGR &= (uint32_t)0x08FFB80CU;
+#endif /* STM32F051x8 or STM32F058x8 */
+
+ /* Reset HSEON, CSSON and PLLON bits */
+ RCC->CR &= (uint32_t)0xFEF6FFFFU;
+
+ /* Reset HSEBYP bit */
+ RCC->CR &= (uint32_t)0xFFFBFFFFU;
+
+ /* Reset PLLSRC, PLLXTPRE and PLLMUL[3:0] bits */
+ RCC->CFGR &= (uint32_t)0xFFC0FFFFU;
+
+ /* Reset PREDIV[3:0] bits */
+ RCC->CFGR2 &= (uint32_t)0xFFFFFFF0U;
+
+#if defined (STM32F072xB) || defined (STM32F078xx)
+ /* Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFFCFE2CU;
+#elif defined (STM32F071xB)
+ /* Reset USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFFFCEACU;
+#elif defined (STM32F091xC) || defined (STM32F098xx)
+ /* Reset USART3SW[1:0], USART2SW[1:0], USART1SW[1:0], I2C1SW, CECSW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFF0FEACU;
+#elif defined (STM32F030x6) || defined (STM32F030x8) || defined (STM32F031x6) || defined (STM32F038xx) || defined (STM32F030xC)
+ /* Reset USART1SW[1:0], I2C1SW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFFFFEECU;
+#elif defined (STM32F051x8) || defined (STM32F058xx)
+ /* Reset USART1SW[1:0], I2C1SW, CECSW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFFFFEACU;
+#elif defined (STM32F042x6) || defined (STM32F048xx)
+ /* Reset USART1SW[1:0], I2C1SW, CECSW, USBSW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFFFFE2CU;
+#elif defined (STM32F070x6) || defined (STM32F070xB)
+ /* Reset USART1SW[1:0], I2C1SW, USBSW and ADCSW bits */
+ RCC->CFGR3 &= (uint32_t)0xFFFFFE6CU;
+ /* Set default USB clock to PLLCLK, since there is no HSI48 */
+ RCC->CFGR3 |= (uint32_t)0x00000080U;
+#else
+ #warning "No target selected"
+#endif
+
+ /* Reset HSI14 bit */
+ RCC->CR2 &= (uint32_t)0xFFFFFFFEU;
+
+ /* Disable all interrupts */
+ RCC->CIR = 0x00000000U;
+
+}
+
+/**
+ * @brief Update SystemCoreClock variable according to Clock Register Values.
+ * The SystemCoreClock variable contains the core clock (HCLK), it can
+ * be used by the user application to setup the SysTick timer or configure
+ * other parameters.
+ *
+ * @note Each time the core clock (HCLK) changes, this function must be called
+ * to update SystemCoreClock variable value. Otherwise, any configuration
+ * based on this variable will be incorrect.
+ *
+ * @note - The system frequency computed by this function is not the real
+ * frequency in the chip. It is calculated based on the predefined
+ * constant and the selected clock source:
+ *
+ * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*)
+ *
+ * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**)
+ *
+ * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**)
+ * or HSI_VALUE(*) multiplied/divided by the PLL factors.
+ *
+ * (*) HSI_VALUE is a constant defined in stm32f0xx_hal.h file (default value
+ * 8 MHz) but the real value may vary depending on the variations
+ * in voltage and temperature.
+ *
+ * (**) HSE_VALUE is a constant defined in stm32f0xx_hal.h file (default value
+ * 8 MHz), user has to ensure that HSE_VALUE is same as the real
+ * frequency of the crystal used. Otherwise, this function may
+ * have wrong result.
+ *
+ * - The result of this function could be not correct when using fractional
+ * value for HSE crystal.
+ *
+ * @param None
+ * @retval None
+ */
+void SystemCoreClockUpdate (void)
+{
+ uint32_t tmp = 0, pllmull = 0, pllsource = 0, predivfactor = 0;
+
+ /* Get SYSCLK source -------------------------------------------------------*/
+ tmp = RCC->CFGR & RCC_CFGR_SWS;
+
+ switch (tmp)
+ {
+ case RCC_CFGR_SWS_HSI: /* HSI used as system clock */
+ SystemCoreClock = HSI_VALUE;
+ break;
+ case RCC_CFGR_SWS_HSE: /* HSE used as system clock */
+ SystemCoreClock = HSE_VALUE;
+ break;
+ case RCC_CFGR_SWS_PLL: /* PLL used as system clock */
+ /* Get PLL clock source and multiplication factor ----------------------*/
+ pllmull = RCC->CFGR & RCC_CFGR_PLLMUL;
+ pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
+ pllmull = ( pllmull >> 18) + 2;
+ predivfactor = (RCC->CFGR2 & RCC_CFGR2_PREDIV) + 1;
+
+ if (pllsource == RCC_CFGR_PLLSRC_HSE_PREDIV)
+ {
+ /* HSE used as PLL clock source : SystemCoreClock = HSE/PREDIV * PLLMUL */
+ SystemCoreClock = (HSE_VALUE/predivfactor) * pllmull;
+ }
+#if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F072xB) || defined(STM32F078xx) || defined(STM32F091xC) || defined(STM32F098xx)
+ else if (pllsource == RCC_CFGR_PLLSRC_HSI48_PREDIV)
+ {
+ /* HSI48 used as PLL clock source : SystemCoreClock = HSI48/PREDIV * PLLMUL */
+ SystemCoreClock = (HSI48_VALUE/predivfactor) * pllmull;
+ }
+#endif /* STM32F042x6 || STM32F048xx || STM32F072xB || STM32F078xx || STM32F091xC || STM32F098xx */
+ else
+ {
+#if defined(STM32F042x6) || defined(STM32F048xx) || defined(STM32F070x6) \
+ || defined(STM32F078xx) || defined(STM32F071xB) || defined(STM32F072xB) \
+ || defined(STM32F070xB) || defined(STM32F091xC) || defined(STM32F098xx) || defined(STM32F030xC)
+ /* HSI used as PLL clock source : SystemCoreClock = HSI/PREDIV * PLLMUL */
+ SystemCoreClock = (HSI_VALUE/predivfactor) * pllmull;
+#else
+ /* HSI used as PLL clock source : SystemCoreClock = HSI/2 * PLLMUL */
+ SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
+#endif /* STM32F042x6 || STM32F048xx || STM32F070x6 ||
+ STM32F071xB || STM32F072xB || STM32F078xx || STM32F070xB ||
+ STM32F091xC || STM32F098xx || STM32F030xC */
+ }
+ break;
+ default: /* HSI used as system clock */
+ SystemCoreClock = HSI_VALUE;
+ break;
+ }
+ /* Compute HCLK clock frequency ----------------*/
+ /* Get HCLK prescaler */
+ tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)];
+ /* HCLK clock frequency */
+ SystemCoreClock >>= tmp;
+}
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
+
diff --git a/gm_platform/fw/tools/gen_cmsis_exports.py b/gm_platform/fw/tools/gen_cmsis_exports.py new file mode 100644 index 0000000..ba3422b --- /dev/null +++ b/gm_platform/fw/tools/gen_cmsis_exports.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +import re +import os + +if __name__ == '__main__': + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument('cmsis_device_header', nargs='+', type=argparse.FileType('rb')) + args = parser.parse_args() + + print('#ifndef __GENERATED_CMSIS_HEADER_EXPORTS__') + print('#define __GENERATED_CMSIS_HEADER_EXPORTS__') + print() + for header in args.cmsis_device_header: + lines = header.readlines() + name = os.path.basename(header.name) + print('#include <{}>'.format(name)) + print() + + print('/* {} */'.format(name)) + for l in lines: + match = re.match(b'^#define (\w+)\s+\W*(\w+_TypeDef|\w+_Type).*$', l) + if match: + inst, typedef = match.groups() + inst, typedef = inst.decode(), typedef.decode() + print('{} *{} = {};'.format(typedef, inst.lower(), inst)) + print() + print('#endif//__GENERATED_CMSIS_HEADER_EXPORTS__') + |