blinkenlights working w sonar
This commit is contained in:
@@ -4,7 +4,7 @@ ARCH_FLAGS = -msoft-float -mfloat-abi=soft
|
||||
ARCH_FLAGS += -mthumb -mcpu=cortex-m3
|
||||
|
||||
# Clock speed constants
|
||||
DEFS += -DF_CPU=8000000UL
|
||||
DEFS += -DF_CPU=72000000UL
|
||||
|
||||
DEFS += -DSTM32F10X_MD
|
||||
DEFS += -DARM_MATH_CM3
|
||||
@@ -113,7 +113,7 @@ LIB_CFLAGS = -Wno-shadow -Wno-float-equal -Wno-inline -Wno-unused-parameter -W
|
||||
###############################################################################
|
||||
# Linker flags
|
||||
|
||||
LDFLAGS += --static -lm -lc -nostartfiles
|
||||
LDFLAGS += --static -lm -lc -nostartfiles -specs=nano.specs
|
||||
LDFLAGS += -Llib
|
||||
LDFLAGS += -T$(LDSCRIPT)
|
||||
LDFLAGS += -Wl,-Map=$(*).map
|
||||
@@ -181,6 +181,7 @@ size: $(BINARY).elf
|
||||
|
||||
%.elf %.map: libcheck $(OBJS) $(HEADERS)
|
||||
$(Q)$(LD) $(LDFLAGS) $(ARCH_FLAGS) $(OBJS) $(LDLIBS) -o $(*).elf
|
||||
$(Q)./parsemap.php
|
||||
$(Q)$(SIZE) $(*).elf
|
||||
|
||||
%.o: %.c
|
||||
|
||||
@@ -11,7 +11,7 @@ INCLUDEPATH += \
|
||||
/usr/arm-none-eabi/include \
|
||||
/usr/lib/gcc/arm-none-eabi/5.3.0/include/
|
||||
|
||||
DEFINES += F_CPU=8000000UL \
|
||||
DEFINES += F_CPU=72000000UL \
|
||||
STM32F10X_MD \
|
||||
USE_STDPERIPH_DRIVER \
|
||||
__null=0 \
|
||||
@@ -61,7 +61,27 @@ HEADERS += \
|
||||
project/stm32f10x_conf.h \
|
||||
project/stm32f10x_it.h \
|
||||
project/system_stm32f10x.h \
|
||||
project/sbmp_config.h
|
||||
project/sbmp_config.h \
|
||||
project/com/com_fileio.h \
|
||||
project/com/com_iface.h \
|
||||
project/com/datalink.h \
|
||||
project/com/debug.h \
|
||||
project/com/iface_noop.h \
|
||||
project/com/iface_usart.h \
|
||||
project/utils/circbuf.h \
|
||||
project/utils/minmax.h \
|
||||
project/utils/timebase.h \
|
||||
project/colorled.h \
|
||||
project/malloc_safe.h \
|
||||
project/hw_init.h \
|
||||
project/utils/debounce.h \
|
||||
project/bus/event_handler.h \
|
||||
project/bus/event_queue.h \
|
||||
project/utils/str_utils.h \
|
||||
project/main.h \
|
||||
project/utils/matcher.h \
|
||||
project/utils/meanbuf.h \
|
||||
project/display.h
|
||||
|
||||
SOURCES += \
|
||||
lib/cmsis/core_cm3.c \
|
||||
@@ -98,7 +118,27 @@ SOURCES += \
|
||||
lib/spl/src/stm32f10x_wwdg.c \
|
||||
project/main.c \
|
||||
project/stm32f10x_it.c \
|
||||
project/system_stm32f10x.c
|
||||
project/system_stm32f10x.c \
|
||||
project/com/com_fileio.c \
|
||||
project/com/com_iface.c \
|
||||
project/com/datalink.c \
|
||||
project/com/debug.c \
|
||||
project/com/iface_noop.c \
|
||||
project/com/iface_usart.c \
|
||||
project/utils/circbuf.c \
|
||||
project/utils/debounce.c \
|
||||
project/utils/timebase.c \
|
||||
project/colorled.c \
|
||||
project/hw_init.c \
|
||||
project/malloc_safe.c \
|
||||
project/spl_assert.c \
|
||||
project/syscalls.c \
|
||||
project/bus/event_handler.c \
|
||||
project/bus/event_queue.c \
|
||||
project/utils/str_utils.c \
|
||||
project/utils/matcher.c \
|
||||
project/utils/meanbuf.c \
|
||||
project/display.c
|
||||
|
||||
DISTFILES += \
|
||||
style.astylerc \
|
||||
|
||||
+75
-148
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE QtCreatorProject>
|
||||
<!-- Written by QtCreator 3.6.1, 2016-05-11T19:11:14. -->
|
||||
<!-- Written by QtCreator 3.6.1, 2016-05-11T22:50:05. -->
|
||||
<qtcreator>
|
||||
<data>
|
||||
<variable>EnvironmentId</variable>
|
||||
@@ -53,7 +53,12 @@
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.PluginSettings</variable>
|
||||
<valuemap type="QVariantMap"/>
|
||||
<valuemap type="QVariantMap">
|
||||
<valuemap type="QVariantMap" key="ClangProjectSettings">
|
||||
<value type="QString" key="CustomPchFile"></value>
|
||||
<value type="int" key="PchUsage">1</value>
|
||||
</valuemap>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
<variable>ProjectExplorer.Project.Target.0</variable>
|
||||
@@ -63,22 +68,11 @@
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">{15262c8f-05de-48ee-9452-3d289b21ba3e}</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveBuildConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">-1</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
|
||||
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">2</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/ondra/devel/build-f103-STLINK-Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/ondra/devel/f103</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
|
||||
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
@@ -88,10 +82,10 @@
|
||||
<value type="QString">-r</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">-B -j 4</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
@@ -119,132 +113,12 @@
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Debug</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">Main</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">2</value>
|
||||
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.1">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/ondra/devel/build-f103-STLINK-Release</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">false</value>
|
||||
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">false</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
|
||||
<value type="QString">-w</value>
|
||||
<value type="QString">-r</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
|
||||
<value type="QString">-w</value>
|
||||
<value type="QString">-r</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Release</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
|
||||
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.2">
|
||||
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">/home/ondra/devel/build-f103-STLINK-Profile</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">qmake</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">QtProjectManager.QMakeBuildStep</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.LinkQmlDebuggingLibrary">true</value>
|
||||
<value type="QString" key="QtProjectManager.QMakeBuildStep.QMakeArguments"></value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.QMakeForced">false</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.SeparateDebugInfo">true</value>
|
||||
<value type="bool" key="QtProjectManager.QMakeBuildStep.UseQtQuickCompiler">false</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.1">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
|
||||
<value type="QString">-w</value>
|
||||
<value type="QString">-r</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">false</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">2</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Build</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Build</value>
|
||||
</valuemap>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.1">
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
|
||||
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.MakeStep</value>
|
||||
<valuelist type="QVariantList" key="Qt4ProjectManager.MakeStep.AutomaticallyAddedMakeArguments">
|
||||
<value type="QString">-w</value>
|
||||
<value type="QString">-r</value>
|
||||
</valuelist>
|
||||
<value type="bool" key="Qt4ProjectManager.MakeStep.Clean">true</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeArguments">clean</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MakeStep.MakeCommand"></value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildStepList.StepsCount">1</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Clean</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.BuildSteps.Clean</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.BuildConfiguration.BuildStepListCount">2</value>
|
||||
<value type="bool" key="ProjectExplorer.BuildConfiguration.ClearSystemEnvironment">false</value>
|
||||
<valuelist type="QVariantList" key="ProjectExplorer.BuildConfiguration.UserEnvironmentChanges"/>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Profile</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">Qt4ProjectManager.Qt4BuildConfiguration</value>
|
||||
<value type="int" key="Qt4ProjectManager.Qt4BuildConfiguration.BuildConfiguration">0</value>
|
||||
<value type="bool" key="Qt4ProjectManager.Qt4BuildConfiguration.UseShadowBuild">true</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">3</value>
|
||||
<value type="int" key="ProjectExplorer.Target.BuildConfigurationCount">1</value>
|
||||
<value type="int" key="ProjectExplorer.Target.DeployConfigurationCount">0</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.PluginSettings"/>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.0">
|
||||
@@ -288,11 +162,11 @@
|
||||
</valuelist>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Arguments"></value>
|
||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable"></value>
|
||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Arguments">flash</value>
|
||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">/usr/bin/make</value>
|
||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory">%{buildDir}</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Custom Executable</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Run /usr/bin/make</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName">make flash</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
@@ -340,13 +214,12 @@
|
||||
<value type="int">13</value>
|
||||
<value type="int">14</value>
|
||||
</valuelist>
|
||||
<value type="QString" key="BareMetal.CustomRunConfig.Executable"></value>
|
||||
<value type="QString" key="BareMetal.RunConfig.WorkingDirectory"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Run on GDB server or hardware debugger</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">f103 (via GDB server or hardware debugger)</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">BareMetal.CustomRunConfig</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">BareMetal/home/ondra/devel/f103/f103.pro</value>
|
||||
<value type="QString" key="Qt4ProjectManager.MaemoRunConfiguration.Arguments"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MaemoRunConfiguration.ProFile"></value>
|
||||
<value type="QString" key="Qt4ProjectManager.MaemoRunConfiguration.ProFile">f103.pro</value>
|
||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
@@ -354,7 +227,61 @@
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">2</value>
|
||||
<valuemap type="QVariantMap" key="ProjectExplorer.Target.RunConfiguration.2">
|
||||
<value type="bool" key="Analyzer.QmlProfiler.FlushEnabled">false</value>
|
||||
<value type="uint" key="Analyzer.QmlProfiler.FlushInterval">1000</value>
|
||||
<value type="QString" key="Analyzer.QmlProfiler.LastTraceFile"></value>
|
||||
<value type="bool" key="Analyzer.QmlProfiler.Settings.UseGlobalSettings">true</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.AddedSuppressionFiles"/>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectBusEvents">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.CollectSystime">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableBranchSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableCacheSim">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Callgrind.EnableEventToolTips">true</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.MinimumCostRatio">0.01</value>
|
||||
<value type="double" key="Analyzer.Valgrind.Callgrind.VisualisationMinimumCostRatio">10</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.FilterExternalIssues">true</value>
|
||||
<value type="int" key="Analyzer.Valgrind.LeakCheckOnFinish">1</value>
|
||||
<value type="int" key="Analyzer.Valgrind.NumCallers">25</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.RemovedSuppressionFiles"/>
|
||||
<value type="int" key="Analyzer.Valgrind.SelfModifyingCodeDetection">1</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.Settings.UseGlobalSettings">true</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.ShowReachable">false</value>
|
||||
<value type="bool" key="Analyzer.Valgrind.TrackOrigins">true</value>
|
||||
<value type="QString" key="Analyzer.Valgrind.ValgrindExecutable">valgrind</value>
|
||||
<valuelist type="QVariantList" key="Analyzer.Valgrind.VisibleErrorKinds">
|
||||
<value type="int">0</value>
|
||||
<value type="int">1</value>
|
||||
<value type="int">2</value>
|
||||
<value type="int">3</value>
|
||||
<value type="int">4</value>
|
||||
<value type="int">5</value>
|
||||
<value type="int">6</value>
|
||||
<value type="int">7</value>
|
||||
<value type="int">8</value>
|
||||
<value type="int">9</value>
|
||||
<value type="int">10</value>
|
||||
<value type="int">11</value>
|
||||
<value type="int">12</value>
|
||||
<value type="int">13</value>
|
||||
<value type="int">14</value>
|
||||
</valuelist>
|
||||
<value type="int" key="PE.EnvironmentAspect.Base">2</value>
|
||||
<valuelist type="QVariantList" key="PE.EnvironmentAspect.Changes"/>
|
||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Arguments"></value>
|
||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.Executable">/home/ondra/devel/f103/main.elf</value>
|
||||
<value type="QString" key="ProjectExplorer.CustomExecutableRunConfiguration.WorkingDirectory">/home/ondra/devel/f103</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DefaultDisplayName">Run /home/ondra/devel/f103/main.elf</value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.DisplayName"></value>
|
||||
<value type="QString" key="ProjectExplorer.ProjectConfiguration.Id">ProjectExplorer.CustomExecutableRunConfiguration</value>
|
||||
<value type="uint" key="RunConfiguration.QmlDebugServerPort">3768</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseCppDebuggerAuto">true</value>
|
||||
<value type="bool" key="RunConfiguration.UseMultiProcess">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
|
||||
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
|
||||
</valuemap>
|
||||
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">3</value>
|
||||
</valuemap>
|
||||
</data>
|
||||
<data>
|
||||
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
#daemon configuration
|
||||
telnet_port 4444
|
||||
gdb_port 3333
|
||||
|
||||
#interface
|
||||
#cat /usr/lib/openocd/interface/olimex-arm-usb-ocd.cfg >> openocd.cfg
|
||||
|
||||
|
||||
|
||||
#
|
||||
# STMicroelectronics ST-LINK/V2 in-circuit debugger/programmer
|
||||
#
|
||||
|
||||
interface hla
|
||||
hla_layout stlink
|
||||
hla_device_desc "ST-LINK/V2"
|
||||
hla_vid_pid 0x0483 0x3748
|
||||
|
||||
# Optionally specify the serial number of ST-LINK/V2 usb device. ST-LINK/V2
|
||||
# devices seem to have serial numbers with unreadable characters. ST-LINK/V2
|
||||
# firmware version >= V2.J21.S4 recommended to avoid issues with adapter serial
|
||||
# number reset issues.
|
||||
# eg.
|
||||
#hla_serial "\xaa\xbc\x6e\x06\x50\x75\xff\x55\x17\x42\x19\x3f"
|
||||
|
||||
|
||||
|
||||
# target configuration
|
||||
# cat /usr/lib/openocd/target/stm32.cfg >> openocd.cfg
|
||||
|
||||
# script for stm32f3x family
|
||||
|
||||
#
|
||||
# stm32 devices support both JTAG and SWD transports.
|
||||
#
|
||||
source [find target/swj-dp.tcl]
|
||||
source [find mem_helper.tcl]
|
||||
|
||||
if { [info exists CHIPNAME] } {
|
||||
set _CHIPNAME $CHIPNAME
|
||||
} else {
|
||||
set _CHIPNAME stm32f3x
|
||||
}
|
||||
|
||||
set _ENDIAN little
|
||||
|
||||
# Work-area is a space in RAM used for flash programming
|
||||
# By default use 16kB
|
||||
if { [info exists WORKAREASIZE] } {
|
||||
set _WORKAREASIZE $WORKAREASIZE
|
||||
} else {
|
||||
set _WORKAREASIZE 0x4000
|
||||
}
|
||||
|
||||
# JTAG speed should be <= F_CPU/6. F_CPU after reset is 8MHz, so use F_JTAG = 1MHz
|
||||
#
|
||||
# Since we may be running of an RC oscilator, we crank down the speed a
|
||||
# bit more to be on the safe side. Perhaps superstition, but if are
|
||||
# running off a crystal, we can run closer to the limit. Note
|
||||
# that there can be a pretty wide band where things are more or less stable.
|
||||
adapter_khz 1000
|
||||
|
||||
adapter_nsrst_delay 100
|
||||
if {[using_jtag]} {
|
||||
jtag_ntrst_delay 100
|
||||
}
|
||||
|
||||
#jtag scan chain
|
||||
if { [info exists CPUTAPID] } {
|
||||
set _CPUTAPID $CPUTAPID
|
||||
} else {
|
||||
if { [using_jtag] } {
|
||||
# See STM Document RM0316
|
||||
# Section 29.6.3 - corresponds to Cortex-M4 r0p1
|
||||
set _CPUTAPID 0x4ba00477
|
||||
} {
|
||||
set _CPUTAPID 0x2ba01477
|
||||
}
|
||||
}
|
||||
|
||||
swj_newdap $_CHIPNAME cpu -irlen 4 -ircapture 0x1 -irmask 0xf -expected-id $_CPUTAPID
|
||||
|
||||
if { [info exists BSTAPID] } {
|
||||
set _BSTAPID $BSTAPID
|
||||
} else {
|
||||
# STM Document RM0316 rev 5 for STM32F302/303 B/C size
|
||||
set _BSTAPID1 0x06422041
|
||||
# STM Document RM0313 rev 3 for STM32F37x
|
||||
set _BSTAPID2 0x06432041
|
||||
# STM Document RM364 rev 1 for STM32F334
|
||||
set _BSTAPID3 0x06438041
|
||||
# STM Document RM316 rev 5 for STM32F303 6/8 size
|
||||
# STM Document RM365 rev 3 for STM32F302 6/8 size
|
||||
# STM Document RM366 rev 2 for STM32F301 6/8 size
|
||||
set _BSTAPID4 0x06439041
|
||||
# STM Document RM016 rev 5 for STM32F303 D/E size
|
||||
set _BSTAPID5 0x06446041
|
||||
}
|
||||
|
||||
if {[using_jtag]} {
|
||||
swj_newdap $_CHIPNAME bs -irlen 5 -expected-id $_BSTAPID1 \
|
||||
-expected-id $_BSTAPID2 -expected-id $_BSTAPID3 \
|
||||
-expected-id $_BSTAPID4 -expected-id $_BSTAPID5
|
||||
}
|
||||
|
||||
set _TARGETNAME $_CHIPNAME.cpu
|
||||
target create $_TARGETNAME cortex_m -endian $_ENDIAN -chain-position $_TARGETNAME
|
||||
|
||||
$_TARGETNAME configure -work-area-phys 0x20000000 -work-area-size $_WORKAREASIZE -work-area-backup 0
|
||||
|
||||
set _FLASHNAME $_CHIPNAME.flash
|
||||
flash bank $_FLASHNAME stm32f1x 0 0 0 0 $_TARGETNAME
|
||||
|
||||
reset_config srst_nogate
|
||||
|
||||
if {![using_hla]} {
|
||||
# if srst is not fitted use SYSRESETREQ to
|
||||
# perform a soft reset
|
||||
cortex_m reset_config sysresetreq
|
||||
}
|
||||
|
||||
proc stm32f3x_default_reset_start {} {
|
||||
# Reset clock is HSI (8 MHz)
|
||||
adapter_khz 1000
|
||||
}
|
||||
|
||||
proc stm32f3x_default_examine_end {} {
|
||||
# Enable debug during low power modes (uses more power)
|
||||
mmw 0xe0042004 0x00000007 0 ;# DBGMCU_CR |= DBG_STANDBY | DBG_STOP | DBG_SLEEP
|
||||
|
||||
# Stop watchdog counters during halt
|
||||
mww 0xe0042008 0x00001800 ;# DBGMCU_APB1_FZ = DBG_IWDG_STOP | DBG_WWDG_STOP
|
||||
}
|
||||
|
||||
proc stm32f3x_default_reset_init {} {
|
||||
# Configure PLL to boost clock to HSI x 8 (64 MHz)
|
||||
mww 0x40021004 0x00380400 ;# RCC_CFGR = PLLMUL[3:1] | PPRE1[2]
|
||||
mmw 0x40021000 0x01000000 0 ;# RCC_CR |= PLLON
|
||||
mww 0x40022000 0x00000012 ;# FLASH_ACR = PRFTBE | LATENCY[1]
|
||||
sleep 10 ;# Wait for PLL to lock
|
||||
mmw 0x40021004 0x00000002 0 ;# RCC_CFGR |= SW[1]
|
||||
|
||||
# Boost JTAG frequency
|
||||
adapter_khz 8000
|
||||
}
|
||||
|
||||
# Default hooks
|
||||
$_TARGETNAME configure -event examine-end { stm32f3x_default_examine_end }
|
||||
$_TARGETNAME configure -event reset-start { stm32f3x_default_reset_start }
|
||||
$_TARGETNAME configure -event reset-init { stm32f3x_default_reset_init }
|
||||
|
||||
$_TARGETNAME configure -event trace-config {
|
||||
# Set TRACE_IOEN; TRACE_MODE is set to async; when using sync
|
||||
# change this value accordingly to configure trace pins
|
||||
# assignment
|
||||
mmw 0xe0042004 0x00000020 0
|
||||
}
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
$map = file_get_contents('main.map');
|
||||
|
||||
$at_flash = strpos($map, '.text 0x0000000008000000');
|
||||
$at_ram = strpos($map, '.data 0x0000000020000000');
|
||||
$at_dbg = strpos($map, '.memory_b1_text');
|
||||
|
||||
$discard = substr($map, 0, $at_flash);
|
||||
$flash = substr($map, $at_flash, $at_ram - $at_flash);
|
||||
$ram = substr($map, $at_ram, $at_dbg - $at_ram);
|
||||
|
||||
$flash = str_replace("lib/gcc/arm-none-eabi/5.3.0/../../../../", "", $flash);
|
||||
|
||||
file_put_contents("main.flash.map", $flash);
|
||||
file_put_contents("main.ram.map", $ram);
|
||||
|
||||
//preg_match("/\*\(\.eh_frame\)\n\s*0x00000000(2[0-9a-f]+)\s*\. = ALIGN \(0x4\)/i", $ram, $m);
|
||||
|
||||
//echo "Free RAM: " . (0x20010000 - hexdec($m[1])) . " B\n";
|
||||
@@ -0,0 +1,159 @@
|
||||
#include "event_handler.h"
|
||||
#include "com/debug.h"
|
||||
|
||||
typedef struct {
|
||||
uint32_t handler_id;
|
||||
uint32_t chained_handler; // if not 0, that handler is removed together with this handler.
|
||||
EventType type; // event type
|
||||
EventHandlerCallback handler; // returns True if event was handled.
|
||||
bool used; // this slot is currently used
|
||||
|
||||
void *user_data;
|
||||
|
||||
} EventHandlerSlot;
|
||||
|
||||
|
||||
#define EH_SLOT_COUNT 6
|
||||
static EventHandlerSlot eh_slots[EH_SLOT_COUNT];
|
||||
|
||||
static uint32_t next_slot_pid = 1; // 0 is reserved
|
||||
|
||||
/** Get a valid free PID for a new handler slot. */
|
||||
static uint32_t make_pid(void)
|
||||
{
|
||||
uint32_t pid = next_slot_pid++;
|
||||
|
||||
// make sure no task is given PID 0
|
||||
if (next_slot_pid == 0) {
|
||||
next_slot_pid++;
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Register an event handler for event type
|
||||
* @param type : handled event type
|
||||
* @param handler : the handler func
|
||||
* @return handler ID. Can be used to remove the handler.
|
||||
*/
|
||||
uint32_t register_event_handler(EventType type, EventHandlerCallback handler, void *user_data)
|
||||
{
|
||||
for (int i = 0; i < EH_SLOT_COUNT; i++) {
|
||||
if (eh_slots[i].used) continue;
|
||||
|
||||
// Free slot found
|
||||
EventHandlerSlot *slot = &eh_slots[i];
|
||||
|
||||
slot->handler = handler;
|
||||
slot->type = type;
|
||||
slot->handler_id = make_pid();
|
||||
slot->used = true;
|
||||
slot->chained_handler = 0;
|
||||
slot->user_data = user_data;
|
||||
|
||||
return slot->handler_id;
|
||||
}
|
||||
|
||||
error("Failed to register event handler for type %d", type);
|
||||
|
||||
return 0; // fail
|
||||
}
|
||||
|
||||
/** Chain for common destruction */
|
||||
bool chain_event_handler(uint32_t from, uint32_t to, bool reci)
|
||||
{
|
||||
uint8_t cnt = 0;
|
||||
|
||||
for (int i = 0; i < EH_SLOT_COUNT; i++) {
|
||||
EventHandlerSlot *slot = &eh_slots[i];
|
||||
|
||||
if (!slot->used) continue;
|
||||
|
||||
if (slot->handler_id == from) {
|
||||
slot->chained_handler = to;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
// link back in two-handler reciprocal link
|
||||
if (reci && slot->handler_id == to) {
|
||||
slot->chained_handler = from;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
if (cnt == (reci ? 2 : 1)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief check if exists
|
||||
*/
|
||||
bool event_handler_exists(uint32_t handler_id)
|
||||
{
|
||||
for (int i = 0; i < EH_SLOT_COUNT; i++) {
|
||||
EventHandlerSlot *slot = &eh_slots[i];
|
||||
if (!slot->used) continue;
|
||||
if (slot->handler_id == handler_id) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove event handler by handler ID
|
||||
* @param handler_id : handler ID, obtained when registering or in the callback.
|
||||
* @return number of removed handlers
|
||||
*/
|
||||
int remove_event_handler(uint32_t handler_id)
|
||||
{
|
||||
int cnt = 0;
|
||||
while (handler_id != 0) { // outer loop because of chained handlers
|
||||
bool suc = false;
|
||||
for (int i = 0; i < EH_SLOT_COUNT; i++) {
|
||||
if (!eh_slots[i].used) {
|
||||
continue; // skip empty slot
|
||||
}
|
||||
|
||||
// Free slot found
|
||||
EventHandlerSlot *slot = &eh_slots[i];
|
||||
if (slot->handler_id == handler_id) {
|
||||
slot->used = false;
|
||||
slot->user_data = NULL;
|
||||
suc = true;
|
||||
cnt++;
|
||||
|
||||
handler_id = slot->chained_handler; // continue with the chained handler.
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!suc) break;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
/** Handle an event */
|
||||
void run_event_handler(Event *evt)
|
||||
{
|
||||
bool handled = false;
|
||||
|
||||
for (int i = 0; i < EH_SLOT_COUNT; i++) {
|
||||
EventHandlerSlot *slot = &eh_slots[i];
|
||||
|
||||
if (!slot->used) continue; // unused
|
||||
|
||||
if (slot->type != evt->type) continue; // wrong type
|
||||
|
||||
handled = slot->handler(slot->handler_id, evt, &slot->user_data);
|
||||
if (handled) break;
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
warn("Unhandled event, type %d", evt->type);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
#include "main.h"
|
||||
#include "event_queue.h"
|
||||
|
||||
typedef bool (*EventHandlerCallback) (uint32_t hdlr_id, Event *evt, void **user_data);
|
||||
|
||||
/**
|
||||
* @brief Register an event handler for event type
|
||||
* @param type : handled event type
|
||||
* @param handler : the handler func
|
||||
* @return handler ID. Can be used to remove the handler.
|
||||
*/
|
||||
uint32_t register_event_handler(EventType type, EventHandlerCallback handler, void *user_data);
|
||||
|
||||
/**
|
||||
* @brief Remove event handler by handler ID
|
||||
* @param handler_id : handler ID, obtained when registering or in the callback.
|
||||
* @return number of removed handlers
|
||||
*/
|
||||
int remove_event_handler(uint32_t handler_id);
|
||||
|
||||
/**
|
||||
* @brief Handle an event
|
||||
* @param event : pointer to the event to handle
|
||||
*/
|
||||
void run_event_handler(Event *event);
|
||||
|
||||
/**
|
||||
* @brief Check if hansler exists
|
||||
* @param handler_id : handler
|
||||
* @return exists
|
||||
*/
|
||||
bool event_handler_exists(uint32_t handler_id);
|
||||
|
||||
/**
|
||||
* @brief Create a link between two handlers (one direction).
|
||||
*
|
||||
* If handler A is linked to handler B, and handler A is removed,
|
||||
* both handlers will perish.
|
||||
*
|
||||
* Make a circle if you need to chain more than two handlers.
|
||||
*
|
||||
* @param from : handler A
|
||||
* @param to : handler B
|
||||
* @param reciprocal : link also from B to A
|
||||
* @return
|
||||
*/
|
||||
bool chain_event_handler(uint32_t from, uint32_t to, bool reciprocal);
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "event_queue.h"
|
||||
#include "com/debug.h"
|
||||
|
||||
/** Task queue */
|
||||
static CircBuf *tq;
|
||||
|
||||
/** Event queue */
|
||||
static CircBuf *eq;
|
||||
|
||||
|
||||
void queues_init(size_t tq_size, size_t eq_size)
|
||||
{
|
||||
tq = cbuf_create(tq_size, sizeof(QueuedTask));
|
||||
eq = cbuf_create(eq_size, sizeof(Event));
|
||||
}
|
||||
|
||||
|
||||
bool tq_post(void (*handler)(void*), void *arg)
|
||||
{
|
||||
QueuedTask task;
|
||||
task.handler = handler;
|
||||
task.arg = arg;
|
||||
|
||||
bool suc = cbuf_append(tq, &task);
|
||||
if (!suc) error("TQ overflow");
|
||||
return suc;
|
||||
}
|
||||
|
||||
|
||||
bool eq_post(const Event *event)
|
||||
{
|
||||
bool suc = cbuf_append(eq, event);
|
||||
if (!suc) {
|
||||
error("EQ overflow, evt %d", event->type);
|
||||
}
|
||||
return suc;
|
||||
}
|
||||
|
||||
|
||||
bool tq_poll_one(void)
|
||||
{
|
||||
QueuedTask task;
|
||||
|
||||
// serve all tasks
|
||||
bool suc = cbuf_pop(tq, &task);
|
||||
|
||||
if (suc) {
|
||||
task.handler(task.arg);
|
||||
}
|
||||
|
||||
return suc;
|
||||
}
|
||||
|
||||
|
||||
void tq_poll(void)
|
||||
{
|
||||
// serve all tasks
|
||||
while (tq_poll_one());
|
||||
}
|
||||
|
||||
|
||||
bool eq_take(Event *dest)
|
||||
{
|
||||
bool suc = cbuf_pop(eq, dest);
|
||||
return suc;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
|
||||
#include "main.h"
|
||||
#include "utils/circbuf.h"
|
||||
|
||||
#define TASK_QUEUE_SIZE 64
|
||||
#define EVENT_QUEUE_SIZE 64
|
||||
|
||||
|
||||
/** Application events */
|
||||
typedef enum {
|
||||
EVENT_ONE // placeholder
|
||||
|
||||
} EventType;
|
||||
|
||||
|
||||
/** Event Queue entry */
|
||||
typedef struct {
|
||||
EventType type;
|
||||
void *data;
|
||||
} Event;
|
||||
|
||||
typedef struct {
|
||||
void (*handler)(void*);
|
||||
void* arg;
|
||||
} QueuedTask;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set up the task and event queues
|
||||
* @param tq_size : number of slots in the task queue
|
||||
* @param eq_size : number of slots in the event queue
|
||||
*/
|
||||
void queues_init(size_t tq_size, size_t eq_size);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Post a task on the task queue, with arg.
|
||||
*
|
||||
* @see tq_post()
|
||||
*
|
||||
* @param handler : task function
|
||||
* @param arg : argument for the handler
|
||||
* @return success
|
||||
*/
|
||||
bool tq_post(void (*handler)(void *), void *arg);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Post an event on the event queue
|
||||
* @param event : pointer to an event to post; will be copied.
|
||||
* @return success
|
||||
*/
|
||||
bool eq_post(const Event *event);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Run all pending tasks on the task queue
|
||||
*/
|
||||
void tq_poll(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Run one pending task on the task queue
|
||||
* @return true if a task was run.
|
||||
*/
|
||||
bool tq_poll_one(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Take one event off the event queue.
|
||||
* @param dest : pointer to a destination event variable.
|
||||
* @return success
|
||||
*/
|
||||
bool eq_take(Event *dest);
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "colorled.h"
|
||||
#include "utils/timebase.h"
|
||||
|
||||
#define LONG_DELAY() for (volatile uint32_t __j = 4; __j > 0; __j--)
|
||||
#define SHORT_DELAY() for (volatile uint32_t __j = 1; __j > 0; __j--)
|
||||
|
||||
static inline
|
||||
__attribute__((always_inline))
|
||||
void colorled_byte(uint8_t b)
|
||||
{
|
||||
for (register volatile uint8_t i = 0; i < 8; i++) {
|
||||
COLORLED_GPIO->BSRR = COLORLED_PIN; // set pin high
|
||||
|
||||
// duty cycle determines bit value
|
||||
if (b & 0x80) {
|
||||
LONG_DELAY();
|
||||
COLORLED_GPIO->BRR = COLORLED_PIN; // set pin low
|
||||
SHORT_DELAY();
|
||||
} else {
|
||||
SHORT_DELAY();
|
||||
COLORLED_GPIO->BRR = COLORLED_PIN; // set pin low
|
||||
LONG_DELAY();
|
||||
}
|
||||
|
||||
b <<= 1; // shift to next bit
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Set one RGB LED color */
|
||||
void colorled_set(uint32_t rgb)
|
||||
{
|
||||
__disable_irq(); // SysTick interrupt when sending data would break the timing
|
||||
|
||||
colorled_byte((rgb & 0x00FF00) >> 8);
|
||||
colorled_byte((rgb & 0xFF0000) >> 16);
|
||||
colorled_byte(rgb & 0x0000FF);
|
||||
|
||||
__enable_irq();
|
||||
|
||||
delay_us(50); // show
|
||||
}
|
||||
|
||||
|
||||
/** Set many RGBs */
|
||||
void colorled_set_many(uint32_t *rgbs, int count)
|
||||
{
|
||||
__disable_irq();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
uint32_t rgb = *rgbs++;
|
||||
colorled_byte((rgb & 0x00FF00) >> 8);
|
||||
colorled_byte((rgb & 0xFF0000) >> 16);
|
||||
colorled_byte(rgb & 0x0000FF);
|
||||
}
|
||||
|
||||
__enable_irq();
|
||||
|
||||
delay_us(50); // show
|
||||
}
|
||||
|
||||
|
||||
void colorled_off(void)
|
||||
{
|
||||
colorled_set(RGB_BLACK);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#pragma once
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
|
||||
#include "main.h"
|
||||
|
||||
/* Exported types ------------------------------------------------------------*/
|
||||
/* Exported constants --------------------------------------------------------*/
|
||||
|
||||
// PB8 - WS2812B data line
|
||||
#define COLORLED_GPIO GPIOB
|
||||
#define COLORLED_PIN GPIO_Pin_12
|
||||
|
||||
#define RGB_RED rgb(255, 0, 0)
|
||||
#define RGB_ORANGE rgb(255, 110, 0)
|
||||
#define RGB_YELLOW rgb(255, 255, 0)
|
||||
#define RGB_LIME rgb(160, 255, 0)
|
||||
#define RGB_GREEN rgb( 0, 255, 0)
|
||||
#define RGB_CYAN rgb( 0, 255, 120)
|
||||
#define RGB_BLUE rgb( 0, 0, 255)
|
||||
#define RGB_MAGENTA rgb(255, 0, 255)
|
||||
#define RGB_WHITE rgb(255, 255, 255)
|
||||
#define RGB_BLACK rgb( 0, 0, 0)
|
||||
|
||||
/**
|
||||
* @brief Struct for easy manipulation of RGB colors.
|
||||
*
|
||||
* Set components in the xrgb.r (etc.) and you will get
|
||||
* the hex in xrgb.num.
|
||||
*/
|
||||
typedef union {
|
||||
|
||||
/** Struct for access to individual color components */
|
||||
struct __attribute__((packed)) {
|
||||
uint8_t b;
|
||||
uint8_t g;
|
||||
uint8_t r;
|
||||
};
|
||||
|
||||
/** RGB color as a single uint32_t */
|
||||
uint32_t num;
|
||||
|
||||
} ws2812_rgb_t;
|
||||
|
||||
/* Exported macros -----------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Compose an RGB color.
|
||||
* @param r, g, b - components 0xFF
|
||||
* @returns integer 0xRRGGBB
|
||||
*/
|
||||
#define rgb(r, g, b) (((0xFF & (r)) << 16) | ((0xFF & (g)) << 8) | (0xFF & (b)))
|
||||
|
||||
/* Get components */
|
||||
#define rgb_r(rgb) (((rgb) >> 16) & 0xFF)
|
||||
#define rgb_g(rgb) (((rgb) >> 8) & 0xFF)
|
||||
#define rgb_b(rgb) ((rgb) & 0xFF)
|
||||
|
||||
/* Exported functions --------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief Turn OFF the rgb LED
|
||||
*/
|
||||
void colorled_off(void);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set color of a WS2812B
|
||||
* @param rgb - color 0xRRGGBB
|
||||
*/
|
||||
void colorled_set(uint32_t rgb);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Set color of multiple chained RGB leds
|
||||
* @param rgbs - array of colors (0xRRGGBB)
|
||||
* @param count - number of LEDs
|
||||
*/
|
||||
void colorled_set_many(uint32_t *rgbs, int count);
|
||||
@@ -0,0 +1,96 @@
|
||||
#include "main.h"
|
||||
|
||||
#include "com_fileio.h"
|
||||
#include "com_iface.h"
|
||||
#include "utils/str_utils.h"
|
||||
|
||||
// Holding fields for ifaces
|
||||
ComIface *debug_iface = NULL;
|
||||
ComIface *data_iface = NULL;
|
||||
|
||||
|
||||
// --- File descriptor names ------------------------------
|
||||
|
||||
struct name_fd {
|
||||
const char *name;
|
||||
const int fd;
|
||||
};
|
||||
|
||||
#define NAME_FD_MAP_LEN 1
|
||||
|
||||
/** pre-assigned file descriptors for names */
|
||||
static const struct name_fd name_fd_map[NAME_FD_MAP_LEN] = {
|
||||
{FNAME_DLNK, FD_DLNK}
|
||||
};
|
||||
|
||||
|
||||
// --- Syscalls -------------------------------------------
|
||||
|
||||
/**
|
||||
* @brief Write to a file by file descriptor.
|
||||
*
|
||||
* @param fd : open file descriptor
|
||||
* @param buf : data to write
|
||||
* @param len : buffer size
|
||||
* @return number of written bytes
|
||||
*/
|
||||
int _write(int fd, const char *buf, int len)
|
||||
{
|
||||
switch (fd) {
|
||||
case FD_STDOUT: return (int)com_tx_block(debug_iface, buf, (size_t)len);
|
||||
case FD_STDERR: return (int)com_tx_block(debug_iface, buf, (size_t)len);
|
||||
case FD_DLNK: return (int)com_tx_block(data_iface, buf, (size_t)len);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// For some reason, reading does not work.
|
||||
#if 0
|
||||
/**
|
||||
* @brief Read from a file descriptor
|
||||
*
|
||||
* @param fd : file descriptor
|
||||
* @param buf : destination buffer
|
||||
* @param len : number of bytes to read
|
||||
* @return actual number of read bytes
|
||||
*/
|
||||
int _read(int fd, char *buf, int len)
|
||||
{
|
||||
switch (fd) {
|
||||
case FD_STDIN: return com_rx_block(debug_iface, buf, len);
|
||||
case FD_ESP: return com_rx_block(esp_iface, buf, len);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief Open a file by name.
|
||||
*
|
||||
* This stub is called by newlib when fopen is used.
|
||||
* It returns a pre-assigned file descriptor based
|
||||
* on the name.
|
||||
*
|
||||
* @note
|
||||
* stdout, stderr, stdin are open implicitly
|
||||
*
|
||||
* @param name : file name
|
||||
* @param flags : file flags (ignored)
|
||||
* @return file descriptor
|
||||
*/
|
||||
int _open(const char *name, int flags, ...)
|
||||
{
|
||||
(void)flags;
|
||||
|
||||
for (int i = 0; i < NAME_FD_MAP_LEN; i++) {
|
||||
if (streq(name_fd_map[i].name, name)) {
|
||||
return name_fd_map[i].fd;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "com_iface.h"
|
||||
|
||||
/** Debug USART iface */
|
||||
extern ComIface *debug_iface;
|
||||
|
||||
/** ESP8266 com iface */
|
||||
extern ComIface *data_iface;
|
||||
|
||||
/** Do-nothing iface */
|
||||
extern ComIface *com_iface_noop;
|
||||
|
||||
|
||||
/** File descriptors for use with built-in "files" */
|
||||
enum {
|
||||
FD_STDIN = 0,
|
||||
FD_STDOUT = 1,
|
||||
FD_STDERR = 2,
|
||||
FD_DLNK = 3,
|
||||
};
|
||||
|
||||
#define FNAME_DLNK "dlnk"
|
||||
@@ -0,0 +1,179 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "com_iface.h"
|
||||
#include "utils/timebase.h"
|
||||
|
||||
// ---- accessor methods ----------------------
|
||||
|
||||
bool com_rx_rdy(ComIface *iface)
|
||||
{
|
||||
return iface->rx_rdy(iface);
|
||||
}
|
||||
|
||||
|
||||
bool com_tx_rdy(ComIface *iface)
|
||||
{
|
||||
return iface->tx_rdy(iface);
|
||||
}
|
||||
|
||||
|
||||
bool com_tx_done(ComIface *iface)
|
||||
{
|
||||
return iface->tx_done(iface);
|
||||
}
|
||||
|
||||
bool com_tx(ComIface *iface, uint8_t b)
|
||||
{
|
||||
return iface->tx(iface, b);
|
||||
}
|
||||
|
||||
|
||||
bool com_rx(ComIface *iface, uint8_t *b)
|
||||
{
|
||||
return iface->rx(iface, (uint8_t*) b);
|
||||
}
|
||||
|
||||
|
||||
bool com_unrx(ComIface *iface, uint8_t b)
|
||||
{
|
||||
if (!iface->unrx) {
|
||||
return false; // not all may have it implemented
|
||||
}
|
||||
return iface->unrx(iface, b);
|
||||
}
|
||||
|
||||
|
||||
size_t com_tx_block(ComIface *iface, const void *blob, size_t size)
|
||||
{
|
||||
return iface->txb(iface, blob, size);
|
||||
}
|
||||
|
||||
|
||||
size_t com_rx_block(ComIface *iface, void *buf, size_t length)
|
||||
{
|
||||
return iface->rxb(iface, buf, length);
|
||||
}
|
||||
|
||||
|
||||
void com_poll(ComIface *iface)
|
||||
{
|
||||
iface->poll(iface);
|
||||
}
|
||||
|
||||
|
||||
bool com_rx_char(ComIface *iface, char * c)
|
||||
{
|
||||
return iface->rx(iface, (uint8_t*) c);
|
||||
}
|
||||
|
||||
|
||||
bool com_tx_char(ComIface *iface, const char c)
|
||||
{
|
||||
return iface->tx(iface, (uint8_t)c);
|
||||
}
|
||||
|
||||
|
||||
/** Read string, terminate with \0. Returns real read size. */
|
||||
size_t com_rx_str(ComIface *iface, char* buf, size_t buflen)
|
||||
{
|
||||
size_t len = iface->rxb(iface, buf, buflen);
|
||||
buf[len] = 0; // zero terminator
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
size_t com_tx_str(ComIface *iface, const char * string)
|
||||
{
|
||||
return iface->txb(iface, string, strlen(string));
|
||||
}
|
||||
|
||||
|
||||
/** Wait for incoming byte */
|
||||
bool com_rx_wait(ComIface *iface, uint16_t timeout)
|
||||
{
|
||||
until_timeout(timeout) {
|
||||
if (iface->rx_rdy(iface)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** Wait for tx buf ready */
|
||||
bool com_tx_rdy_wait(ComIface *iface, uint16_t timeout)
|
||||
{
|
||||
until_timeout(timeout) {
|
||||
if (iface->tx_rdy(iface)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** Wait for tx complete */
|
||||
bool com_tx_done_wait(ComIface *iface, uint16_t timeout)
|
||||
{
|
||||
until_timeout(timeout) {
|
||||
if (iface->tx_done(iface)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
void com_printf(ComIface *iface, const char *fmt, ...)
|
||||
{
|
||||
if (iface->file == NULL) {
|
||||
com_tx_str(iface, "com_printf(), no iface file!\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// use the file descriptor attached
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
vfprintf(iface->file, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
|
||||
void com_vprintf(ComIface *iface, const char *fmt, va_list va)
|
||||
{
|
||||
if (iface->file == NULL) {
|
||||
com_tx_str(iface, "com_vprintf(), no iface file!\r\n");
|
||||
com_tx_str(iface, fmt); // poor mans fallback
|
||||
return;
|
||||
}
|
||||
|
||||
// use the file descriptor attached
|
||||
vfprintf(iface->file, fmt, va);
|
||||
}
|
||||
|
||||
|
||||
void com_v100_attr_(ComIface *iface, uint8_t count, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, count);
|
||||
|
||||
com_tx_char(iface, 27);
|
||||
com_tx_char(iface, '[');
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
int attr = va_arg(va, int);
|
||||
|
||||
// comma
|
||||
if (i > 0) com_tx_char(iface, ';');
|
||||
|
||||
// number
|
||||
com_printf(iface, "%d", attr);
|
||||
}
|
||||
|
||||
com_tx_char(iface, 'm');
|
||||
|
||||
va_end(va);
|
||||
}
|
||||
@@ -0,0 +1,168 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// Implementation-independent UI (command handler)
|
||||
|
||||
typedef struct ComIface_struct ComIface;
|
||||
|
||||
struct ComIface_struct {
|
||||
// --- Variables ---
|
||||
|
||||
/** Implementation-specific data object */
|
||||
void *opts;
|
||||
|
||||
/** File descriptor for this stream */
|
||||
FILE *file;
|
||||
|
||||
/**
|
||||
* User callback for data ready, triggered on poll().
|
||||
* Can be null.
|
||||
*/
|
||||
void (*rx_callback)(ComIface *iface);
|
||||
|
||||
// --- Interface methods ---
|
||||
|
||||
/** Data ready to be read (RX buffer Not Empty) */
|
||||
bool (*rx_rdy)(ComIface *iface);
|
||||
|
||||
/** Free space in TX buffer */
|
||||
bool (*tx_rdy)(ComIface *iface);
|
||||
|
||||
/** Everything sent */
|
||||
bool (*tx_done)(ComIface *iface);
|
||||
|
||||
/** Send 1 byte. Blocking, timeout after some time. */
|
||||
bool (*tx)(ComIface *iface, uint8_t b);
|
||||
|
||||
/** Read one byte. False on failure. Blocking, timeout after some time. */
|
||||
bool (*rx)(ComIface *iface, uint8_t *b);
|
||||
|
||||
/** Unreceive one byte. False on failure. */
|
||||
bool (*unrx)(ComIface *iface, uint8_t b);
|
||||
|
||||
/** Send a binary block. False on failure. */
|
||||
size_t (*txb)(ComIface *iface, const void *blob, size_t size);
|
||||
|
||||
/** Read a binary block. Returns real read length. Blocking, timeout after some time. */
|
||||
size_t (*rxb)(ComIface *iface, void *buf, size_t length);
|
||||
|
||||
/** Poll for changes */
|
||||
void (*poll)(ComIface *iface);
|
||||
};
|
||||
|
||||
|
||||
// ---- Functions for working with iface --------------
|
||||
|
||||
/** Wait for incoming byte */
|
||||
bool com_rx_wait(ComIface *iface, uint16_t timeout);
|
||||
|
||||
/** Wait for free space in tx buffer */
|
||||
bool com_tx_rdy_wait(ComIface *iface, uint16_t timeout);
|
||||
|
||||
/** Wait for tx complete */
|
||||
bool com_tx_done_wait(ComIface *iface, uint16_t timeout);
|
||||
|
||||
/** Check if there's data in the receive buffer */
|
||||
bool com_rx_rdy(ComIface *iface);
|
||||
|
||||
/** Check if transmit buffer can accept data */
|
||||
bool com_tx_rdy(ComIface *iface);
|
||||
|
||||
/** Check if transmit buffer is empty */
|
||||
bool com_tx_done(ComIface *iface);
|
||||
|
||||
/** Send 1 byte */
|
||||
bool com_tx(ComIface *iface, uint8_t b);
|
||||
|
||||
/** Read one byte. False on failure. Fails on timeout. */
|
||||
bool com_rx(ComIface *iface, uint8_t *b);
|
||||
|
||||
/** Unrx one byte. False on failure. */
|
||||
bool com_unrx(ComIface *iface, uint8_t b);
|
||||
|
||||
/** Send a binary blob. False on failure. Fails on timeout. */
|
||||
size_t com_tx_block(ComIface *iface, const void *blob, size_t size);
|
||||
|
||||
/** Read a blob. Returns real read length. Stops on timeout. */
|
||||
size_t com_rx_block(ComIface *iface, void *buf, size_t length);
|
||||
|
||||
/** Poll for changes */
|
||||
void com_poll(ComIface *iface);
|
||||
|
||||
/** Send 1 char */
|
||||
bool com_tx_char(ComIface *iface, char c);
|
||||
|
||||
/** Read one char. False on failure. Fails on timeout. */
|
||||
bool com_rx_char(ComIface *iface, char *c);
|
||||
|
||||
/** Send a string. False on failure. */
|
||||
size_t com_tx_str(ComIface *iface, const char *str);
|
||||
|
||||
/** Read a string. Returns real read length. Stops on timeout. */
|
||||
size_t com_rx_str(ComIface *iface, char *buf, size_t length);
|
||||
|
||||
|
||||
/**
|
||||
* Printf to a serial interface.
|
||||
* Max length is 255 chars.
|
||||
*/
|
||||
void com_printf(ComIface *iface, const char *fmt, ...)
|
||||
__attribute__ ((format (printf, 2, 3)));
|
||||
|
||||
|
||||
/**
|
||||
* Printf to a serial interface, with va_list.
|
||||
*/
|
||||
void com_vprintf(ComIface *iface, const char *fmt, va_list va);
|
||||
|
||||
|
||||
// ---- VT100/ANSI color support -------------
|
||||
|
||||
/** ANSI formatting attributes */
|
||||
typedef enum {
|
||||
// Non-colour Attributes
|
||||
FMT_RESET = 0, // Reset all attributes
|
||||
FMT_BRIGHT = 1, // Bright
|
||||
FMT_DIM = 2, // Dim
|
||||
FMT_UNDER = 4, // Underscore
|
||||
FMT_BLINK = 5, // Blink
|
||||
FMT_INVERS = 7, // Reverse
|
||||
FMT_HIDDEN = 8, // Hidden
|
||||
FMT_ITALIC = 16, // Italic font
|
||||
FMT_FAINT = 32, // Faint color
|
||||
|
||||
// Foreground Colours
|
||||
FMT_BLACK = 30, // Black
|
||||
FMT_RED = 31, // Red
|
||||
FMT_GREEN = 32, // Green
|
||||
FMT_YELLOW = 33, // Yellow
|
||||
FMT_BLUE = 34, // Blue
|
||||
FMT_MAGENTA = 35, // Magenta
|
||||
FMT_CYAN = 36, // Cyan
|
||||
FMT_WHITE = 37, // White
|
||||
|
||||
// Background Colours
|
||||
FMT_BLACK_BG = 40, // Black
|
||||
FMT_RED_BG = 41, // Red
|
||||
FMT_GREEN_BG = 42, // Green
|
||||
FMT_YELLOW_BG = 43, // Yellow
|
||||
FMT_BLUE_BG = 44, // Blue
|
||||
FMT_MAGENTA_BG = 45, // Magenta
|
||||
FMT_CYAN_BG = 46, // Cyan
|
||||
FMT_WHITE_BG = 47, // White
|
||||
} ANSI_attr_t;
|
||||
|
||||
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1)
|
||||
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N
|
||||
|
||||
#define com_v100_attr(iface, ...) com_v100_attr_(iface, VA_NUM_ARGS(__VA_ARGS__), __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* Send formatting code to a com interface
|
||||
*/
|
||||
void com_v100_attr_(ComIface *iface, uint8_t count, ...);
|
||||
@@ -0,0 +1,48 @@
|
||||
#include "datalink.h"
|
||||
#include "com_fileio.h"
|
||||
#include "debug.h"
|
||||
#include "com_fileio.h"
|
||||
|
||||
SBMP_Endpoint *dlnk_ep;
|
||||
|
||||
static void dlnk_tx(uint8_t b);
|
||||
static void dlnk_rx_bridge(ComIface *iface);
|
||||
|
||||
/** Set up the datalink */
|
||||
void dlnk_init(void)
|
||||
{
|
||||
// Allocate & setup the endpoint
|
||||
dlnk_ep = sbmp_ep_init(NULL, NULL, 100, dlnk_rx, dlnk_tx);
|
||||
sbmp_ep_seed_session(dlnk_ep, 0x3FFF); // just in case arbitration fails
|
||||
sbmp_ep_enable(dlnk_ep, true);
|
||||
|
||||
sbmp_ep_init_listeners(dlnk_ep, NULL, 4); // really don' need many here..
|
||||
|
||||
data_iface->rx_callback = dlnk_rx_bridge;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bridge between USART subsystem's Rx buffer, and the SBMP driver
|
||||
*
|
||||
* Called if bytes are received in the USART buffer,
|
||||
* and the USART subsystem is polled.
|
||||
*/
|
||||
static void dlnk_rx_bridge(ComIface *iface)
|
||||
{
|
||||
uint8_t b;
|
||||
while (com_rx(iface, &b)) {
|
||||
SBMP_RxStatus st = sbmp_ep_receive(dlnk_ep, b);
|
||||
|
||||
// If byte was not accepted, try to put it back into the buffer
|
||||
if (st == SBMP_RX_BUSY || st == SBMP_RX_DISABLED) {
|
||||
com_unrx(iface, b);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Datalink Tx func */
|
||||
static void dlnk_tx(uint8_t b)
|
||||
{
|
||||
com_tx(data_iface, b);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* SBMP setup & funcs
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
#include <sbmp.h>
|
||||
|
||||
#define DG_REQUEST_RAW 40 // request raw vector. Sample count [u16], Frequency [u32]
|
||||
#define DG_REQUEST_FFT 41 // request fft vector. Sample count [u16], Frequency [u32]. Result - count/2 bins. Count must be 2^n, 16..2048
|
||||
#define DG_REQUEST_STORE_REF 42 // calculate signal signature & store for comparing
|
||||
#define DG_REQUEST_COMPARE_REF 43
|
||||
// wifi status & control
|
||||
#define DG_SETMODE_AP 44 // request AP mode (AP button pressed)
|
||||
#define DG_WPS_START 45 // start WPS
|
||||
#define DG_WIFI_STATUS 46 // WiFi status report
|
||||
#define DG_REQUEST_STM_VERSION 47 // Get acquisition module firmware version
|
||||
|
||||
|
||||
extern SBMP_Endpoint *dlnk_ep;
|
||||
|
||||
void dlnk_init(void);
|
||||
|
||||
/** Received datagram handler */
|
||||
extern void dlnk_rx(SBMP_Datagram *dg);
|
||||
@@ -0,0 +1,108 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "com_iface.h"
|
||||
|
||||
#include "utils/timebase.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
|
||||
void dbg_printf(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
com_vprintf(debug_iface, fmt, va); // vsnprintf(strbuf, DBG_BUF_LEN, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
|
||||
void dbg_va_base(const char *fmt, const char *tag, va_list va)
|
||||
{
|
||||
ms_time_t now = ms_now();
|
||||
uint32_t secs = now / 1000;
|
||||
uint32_t ms = now % 1000;
|
||||
|
||||
com_printf(debug_iface, "%4"PRIu32".%03"PRIu32" ", secs, ms);
|
||||
|
||||
dbg_raw(tag);
|
||||
|
||||
com_vprintf(debug_iface, fmt, va);
|
||||
dbg_raw(DEBUG_EOL);
|
||||
}
|
||||
|
||||
/** Print a log message with an INFO tag and newline (ONLY FOR BANNER - always shown) */
|
||||
void banner_info(const char *fmt, ...)
|
||||
{
|
||||
com_v100_attr(debug_iface, FMT_GREEN);
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
dbg_va_base(fmt, DEBUG_TAG_INFO, va);
|
||||
va_end(va);
|
||||
|
||||
com_v100_attr(debug_iface, FMT_RESET);
|
||||
}
|
||||
|
||||
|
||||
#if VERBOSE_LOGGING
|
||||
|
||||
/** Print a log message with a DEBUG tag and newline */
|
||||
void dbg(const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
dbg_va_base(fmt, DEBUG_TAG_BASE, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
|
||||
/** Print a log message with an INFO tag and newline */
|
||||
void info(const char *fmt, ...) __attribute__((alias("banner_info")));
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/** Print a log message with an INFO tag and newline */
|
||||
void banner(const char *fmt, ...)
|
||||
{
|
||||
com_v100_attr(debug_iface, FMT_GREEN, FMT_BRIGHT);
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
dbg_va_base(fmt, DEBUG_TAG_INFO, va);
|
||||
va_end(va);
|
||||
|
||||
com_v100_attr(debug_iface, FMT_RESET);
|
||||
}
|
||||
|
||||
|
||||
/** Print a log message with a warning tag and newline */
|
||||
void warn(const char *fmt, ...)
|
||||
{
|
||||
com_v100_attr(debug_iface, FMT_YELLOW, FMT_BRIGHT);
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
dbg_va_base(fmt, DEBUG_TAG_WARN, va);
|
||||
va_end(va);
|
||||
|
||||
com_v100_attr(debug_iface, FMT_RESET);
|
||||
}
|
||||
|
||||
|
||||
/** Print a log message with an ERROR tag and newline */
|
||||
void error(const char *fmt, ...)
|
||||
{
|
||||
com_v100_attr(debug_iface, FMT_RED, FMT_BRIGHT);
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
dbg_va_base(fmt, DEBUG_TAG_ERROR, va);
|
||||
va_end(va);
|
||||
|
||||
com_v100_attr(debug_iface, FMT_RESET);
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#include "main.h"
|
||||
#include "com_iface.h"
|
||||
#include "com_fileio.h"
|
||||
|
||||
#include "bus/event_queue.h"
|
||||
|
||||
// helper to mark printf functions
|
||||
#define PRINTF_LIKE __attribute__((format(printf, 1, 2)))
|
||||
|
||||
#define DBG_BUF_LEN 256
|
||||
|
||||
#define ESCAPE_DEBUG_MESSAGES 1
|
||||
|
||||
|
||||
// formatting symbols
|
||||
#define DEBUG_EOL "\r\n"
|
||||
#define DEBUG_TAG_WARN "[W] "
|
||||
#define DEBUG_TAG_ERROR "[E] "
|
||||
#define DEBUG_TAG_BASE "[ ] "
|
||||
#define DEBUG_TAG_INFO "[i] "
|
||||
|
||||
|
||||
/** Print a log message with no tag and no newline */
|
||||
void dbg_printf(const char *fmt, ...) PRINTF_LIKE;
|
||||
|
||||
/** Print via va_list */
|
||||
void dbg_va_base(const char *fmt, const char *tag, va_list va);
|
||||
|
||||
/** Print a string to the debug interface (length not limited) */
|
||||
static inline void dbg_raw(const char *str)
|
||||
{
|
||||
com_tx_str(debug_iface, str);
|
||||
}
|
||||
|
||||
|
||||
/** Print a char to the debug interface */
|
||||
static inline void dbg_raw_c(char c)
|
||||
{
|
||||
com_tx(debug_iface, (uint8_t)c);
|
||||
}
|
||||
|
||||
|
||||
#if VERBOSE_LOGGING
|
||||
|
||||
/** Print a log message with a "debug" tag and newline */
|
||||
void dbg(const char *fmt, ...) PRINTF_LIKE;
|
||||
|
||||
|
||||
/** Print a log message with an "info" tag and newline */
|
||||
void info(const char *fmt, ...) PRINTF_LIKE;
|
||||
|
||||
#else
|
||||
|
||||
#define dbg(fmt, ...)
|
||||
#define info(fmt, ...)
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/** Print a log message with an "info" tag and newline */
|
||||
void banner_info(const char *fmt, ...) PRINTF_LIKE;
|
||||
|
||||
/** Print a log message with a "banner" tag and newline */
|
||||
void banner(const char *fmt, ...) PRINTF_LIKE;
|
||||
|
||||
/** Print a log message with a "warning" tag and newline */
|
||||
void warn(const char *fmt, ...) PRINTF_LIKE;
|
||||
|
||||
|
||||
/** Print a log message with an "error" tag and newline */
|
||||
void error(const char *fmt, ...) PRINTF_LIKE;
|
||||
@@ -0,0 +1,91 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "iface_noop.h"
|
||||
#include "com_fileio.h"
|
||||
#include "malloc_safe.h"
|
||||
|
||||
// ==== NOOP com driver ====
|
||||
|
||||
static bool if_rx_rdy(ComIface *iface)
|
||||
{
|
||||
(void)iface;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool if_tx_rdy(ComIface *iface)
|
||||
{
|
||||
(void)iface;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool if_tx_done(ComIface *iface)
|
||||
{
|
||||
(void)iface;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool if_rx(ComIface *iface, uint8_t *b)
|
||||
{
|
||||
(void)iface;
|
||||
(void)b;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool if_unrx(ComIface *iface, uint8_t b)
|
||||
{
|
||||
(void)iface;
|
||||
(void)b;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool if_tx(ComIface *iface, uint8_t b)
|
||||
{
|
||||
(void)iface;
|
||||
(void)b;
|
||||
return true;
|
||||
}
|
||||
|
||||
static size_t if_rxb(ComIface *iface, void *buf, size_t buflen)
|
||||
{
|
||||
(void)iface;
|
||||
(void)buf;
|
||||
(void)buflen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t if_txb(ComIface *iface, const void *blob, size_t size)
|
||||
{
|
||||
(void)iface;
|
||||
(void)blob;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static void if_poll(ComIface *iface)
|
||||
{
|
||||
(void)iface;
|
||||
}
|
||||
|
||||
ComIface *com_noop_init(void)
|
||||
{
|
||||
ComIface *iface = malloc_s(sizeof(ComIface));
|
||||
|
||||
iface->rx_rdy = if_rx_rdy;
|
||||
iface->tx_rdy = if_tx_rdy;
|
||||
iface->tx_done = if_tx_done;
|
||||
|
||||
iface->rx = if_rx;
|
||||
iface->unrx = if_unrx;
|
||||
iface->tx = if_tx;
|
||||
|
||||
iface->rxb = if_rxb;
|
||||
iface->txb = if_txb;
|
||||
|
||||
iface->poll = if_poll;
|
||||
iface->rx_callback = NULL;
|
||||
|
||||
return iface;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* NOOP iface works like /dev/null
|
||||
*/
|
||||
|
||||
#include "com_iface.h"
|
||||
|
||||
/**
|
||||
* @brief Initialize a do-nothing interface.
|
||||
* @param iface : iface pointer. If NULL, it'll be allocated.
|
||||
* @return the iface pointer.
|
||||
*/
|
||||
ComIface *com_noop_init(void);
|
||||
@@ -0,0 +1,328 @@
|
||||
#include "main.h"
|
||||
#include "malloc_safe.h"
|
||||
#include "iface_usart.h"
|
||||
|
||||
#include "utils/timebase.h"
|
||||
#include "utils/circbuf.h"
|
||||
|
||||
#include "com/com_fileio.h"
|
||||
#include "com/debug.h"
|
||||
|
||||
#include "bus/event_queue.h"
|
||||
|
||||
|
||||
#define DEF_WAIT_TO_MS 5
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint16_t wait_timeout;
|
||||
USART_TypeDef *dev;
|
||||
CircBuf *rxbuf; // allocated receive buffer
|
||||
CircBuf *txbuf; // allocated transmit buffer, can be NULL -> no buffer
|
||||
} usart_opts;
|
||||
|
||||
#define opts(iface) ((usart_opts *)(iface)->opts)
|
||||
|
||||
// ---- Instances ----
|
||||
// (needed for async rx/tx with interrupts)
|
||||
|
||||
static ComIface *usart1_iface = NULL;
|
||||
static ComIface *usart2_iface = NULL;
|
||||
static ComIface *usart3_iface = NULL;
|
||||
|
||||
// -------------------
|
||||
|
||||
|
||||
/** Check if data is ready for reading */
|
||||
static bool if_rx_rdy(ComIface *iface)
|
||||
{
|
||||
CircBuf *buf = opts(iface)->rxbuf;
|
||||
|
||||
return !cbuf_empty(buf);
|
||||
}
|
||||
|
||||
|
||||
/** Check if sending is done */
|
||||
static bool if_tx_rdy(ComIface *iface)
|
||||
{
|
||||
CircBuf *buf = opts(iface)->txbuf;
|
||||
|
||||
if (buf == NULL) {
|
||||
// non-buffered mode
|
||||
USART_TypeDef* USARTx = opts(iface)->dev;
|
||||
return (USARTx->SR & USART_SR_TXE);
|
||||
}
|
||||
|
||||
return !cbuf_full(buf);
|
||||
}
|
||||
|
||||
|
||||
/** Check if sending is done */
|
||||
static bool if_tx_done(ComIface *iface)
|
||||
{
|
||||
CircBuf *buf = opts(iface)->txbuf;
|
||||
USART_TypeDef* USARTx = opts(iface)->dev;
|
||||
|
||||
// NULL buffer is considered empty
|
||||
return cbuf_empty(buf) && (USARTx->SR & USART_SR_TC);
|
||||
}
|
||||
|
||||
|
||||
/** Read one byte (wait for it). False on error. */
|
||||
static bool if_rx(ComIface *iface, uint8_t *b)
|
||||
{
|
||||
// wait for data in the buffer
|
||||
if (!com_rx_wait(iface, opts(iface)->wait_timeout) || b == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// read from buffer
|
||||
cbuf_pop(opts(iface)->rxbuf, b);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Try to unreceive a byte. False on error. */
|
||||
static bool if_unrx(ComIface *iface, uint8_t b)
|
||||
{
|
||||
// push back
|
||||
return cbuf_push(opts(iface)->rxbuf, &b);
|
||||
}
|
||||
|
||||
|
||||
/** Send one byte (waits for tx) */
|
||||
static bool if_tx(ComIface *iface, uint8_t b)
|
||||
{
|
||||
usart_opts *uopts = opts(iface);
|
||||
USART_TypeDef* USARTx = uopts->dev;
|
||||
|
||||
if (uopts->txbuf == NULL) {
|
||||
|
||||
// Blocking tx mode
|
||||
until_timeout(uopts->wait_timeout) {
|
||||
if (USARTx->SR & USART_SR_TXE) {
|
||||
USARTx->DR = b;
|
||||
return true; // success
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
} else {
|
||||
|
||||
// Buffered mode
|
||||
|
||||
// wait for free space in the buffer
|
||||
bool ready = com_tx_rdy_wait(iface, uopts->wait_timeout);
|
||||
|
||||
if (ready) {
|
||||
// append to the buffer
|
||||
cbuf_append(uopts->txbuf, &b);
|
||||
}
|
||||
|
||||
// regardless ready state, start Tx if there are bytes
|
||||
// (should fix a bug where full buffer was never emptied)
|
||||
|
||||
// If TXE (send buffer empty), start sending the buffer
|
||||
// Otherwise, IRQ chain is in progress.
|
||||
if (USARTx->SR & USART_SR_TXE) {
|
||||
USART_ITConfig(USARTx, USART_IT_TXE, ENABLE); // start tx chain
|
||||
}
|
||||
|
||||
return ready;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Read a blob. Returns real read size */
|
||||
static size_t if_rxb(ComIface *iface, void *buf, size_t buflen)
|
||||
{
|
||||
if (buf == NULL) return false;
|
||||
//if (!com_rx_wait(iface, opts(iface)->wait_timeout)) return 0;
|
||||
|
||||
uint8_t* byteptr = (uint8_t*)buf;
|
||||
for (size_t i = 0; i < buflen; i++) {
|
||||
if (!if_rx(iface, byteptr++)) return i;
|
||||
}
|
||||
|
||||
return buflen;
|
||||
}
|
||||
|
||||
|
||||
/** Send a binary blob. False on error. */
|
||||
static size_t if_txb(ComIface *iface, const void *blob, size_t size)
|
||||
{
|
||||
if (blob == NULL) return false;
|
||||
//if (!com_tx_rdy_wait(iface, opts(iface)->wait_timeout)) return false;
|
||||
|
||||
const uint8_t* byteptr = (const uint8_t*)blob;
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
if (!if_tx(iface, *byteptr++)) return i;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
/** Check for incoming data */
|
||||
static void if_poll(ComIface *iface)
|
||||
{
|
||||
if (if_rx_rdy(iface)) {
|
||||
// call user cb
|
||||
if (iface->rx_callback) {
|
||||
iface->rx_callback(iface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---- Init interface ----
|
||||
|
||||
//void usart_iface_set_baudrate(ComIface *iface, uint32_t baud)
|
||||
//{
|
||||
// USART_TypeDef* USARTx = opts(iface)->dev;
|
||||
//
|
||||
// USART_SetBaudrate(USARTx, baud);
|
||||
//}
|
||||
|
||||
|
||||
/* public */
|
||||
ComIface *usart_iface_init(USART_TypeDef* USARTx, uint32_t baud, size_t rxbuf_len, size_t txbuf_len)
|
||||
{
|
||||
assert_param(IS_USART_BAUDRATE(baud));
|
||||
assert_param(rxbuf_len > 0);
|
||||
|
||||
ComIface *iface = malloc_s(sizeof(ComIface));
|
||||
|
||||
// --- setup device specific iface data ---
|
||||
|
||||
// Allocate the opts config object
|
||||
iface->opts = malloc_s(sizeof(usart_opts));
|
||||
|
||||
// Set device ID
|
||||
opts(iface)->dev = USARTx;
|
||||
opts(iface)->wait_timeout = DEF_WAIT_TO_MS;
|
||||
|
||||
// Initialize the rx/tx buffers (malloc's the array)
|
||||
opts(iface)->rxbuf = cbuf_create(rxbuf_len, 1);
|
||||
|
||||
// zero-length TX buffer -> blocking Tx
|
||||
opts(iface)->txbuf = (txbuf_len == 0) ? NULL : cbuf_create(txbuf_len, 1);
|
||||
|
||||
// --- driver instance ---
|
||||
|
||||
iface->rx_rdy = if_rx_rdy;
|
||||
iface->tx_rdy = if_tx_rdy;
|
||||
iface->tx_done = if_tx_done;
|
||||
|
||||
iface->rx = if_rx;
|
||||
iface->unrx = if_unrx;
|
||||
iface->tx = if_tx;
|
||||
|
||||
iface->txb = if_txb;
|
||||
iface->rxb = if_rxb;
|
||||
|
||||
iface->poll = if_poll;
|
||||
|
||||
iface->rx_callback = NULL; // user can replace
|
||||
|
||||
|
||||
/* enable peripehral clock, assign to holder var, enable IRQ */
|
||||
IRQn_Type irqn;
|
||||
|
||||
if (USARTx == USART1) {
|
||||
// USART1
|
||||
usart1_iface = iface;
|
||||
irqn = USART1_IRQn;
|
||||
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
|
||||
|
||||
} else if (USARTx == USART2) {
|
||||
// USART2
|
||||
usart2_iface = iface;
|
||||
irqn = USART2_IRQn;
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
|
||||
|
||||
} else {
|
||||
// USART3
|
||||
usart3_iface = iface;
|
||||
irqn = USART3_IRQn;
|
||||
RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
|
||||
}
|
||||
|
||||
// Enable IRQ
|
||||
NVIC_EnableIRQ(irqn);
|
||||
|
||||
// lower priority than SysTick, but high
|
||||
NVIC_SetPriority(irqn, 1); // function does the shifting
|
||||
|
||||
|
||||
/* Setup UART parameters. */
|
||||
USART_InitTypeDef usart;
|
||||
USART_StructInit(&usart);
|
||||
usart.USART_BaudRate = baud;
|
||||
USART_Init(USARTx, &usart);
|
||||
|
||||
/* Enable */
|
||||
USART_Cmd(USARTx, ENABLE);
|
||||
|
||||
// Enable Rx interrupt
|
||||
USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE); // disable IRQ
|
||||
|
||||
return iface;
|
||||
}
|
||||
|
||||
|
||||
// ---- IRQ handlers for chained writing and rx ----
|
||||
|
||||
|
||||
/**
|
||||
* @brief Common USART irq handler
|
||||
* @param iface the interface at which the event occured
|
||||
*/
|
||||
static void usart_iface_irq_base(ComIface* iface)
|
||||
{
|
||||
USART_TypeDef* USARTx = opts(iface)->dev;
|
||||
|
||||
if (USARTx->SR & USART_SR_RXNE) {
|
||||
// Byte received.
|
||||
uint8_t rxb = USARTx->DR & 0xFF;
|
||||
if (!cbuf_append(opts(iface)->rxbuf, &rxb)) {
|
||||
// Buffer overflow
|
||||
// Can't print debug msg, can cause deadlock
|
||||
}
|
||||
}
|
||||
|
||||
if (USARTx->SR & USART_SR_TXE) {
|
||||
// Byte sent.
|
||||
uint8_t txb;
|
||||
|
||||
// Send next byte (if buffer is NULL, cbuf_pop also returns false)
|
||||
if (cbuf_pop(opts(iface)->txbuf, &txb)) {
|
||||
USARTx->DR = txb; // send data
|
||||
} else {
|
||||
USART_ITConfig(USARTx, USART_IT_TXE, DISABLE); // disable IRQ
|
||||
}
|
||||
}
|
||||
|
||||
// Clear ORE flag if set
|
||||
USART_ClearFlag(USARTx, USART_FLAG_ORE);
|
||||
}
|
||||
|
||||
|
||||
void USART1_IRQHandler(void)
|
||||
{
|
||||
usart_iface_irq_base(usart1_iface);
|
||||
}
|
||||
|
||||
|
||||
void USART2_IRQHandler(void)
|
||||
{
|
||||
usart_iface_irq_base(usart2_iface);
|
||||
}
|
||||
|
||||
|
||||
void USART3_IRQHandler(void)
|
||||
{
|
||||
usart_iface_irq_base(usart3_iface);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include "main.h"
|
||||
#include "com_iface.h"
|
||||
|
||||
// Hardware USART.
|
||||
|
||||
/**
|
||||
* @brief Init an USART interface. Caller must configure GPIO's & AF manually.
|
||||
* @param USARTx device
|
||||
* @param baud baud rate (ex.: 9600)
|
||||
* @param rxbuf_len receive buffer size, must be > 0
|
||||
* @param txbuf_len send buffer size. If 0, tx is blocking.
|
||||
* @return the iface structure
|
||||
*/
|
||||
ComIface *usart_iface_init(USART_TypeDef* USARTx, uint32_t baud, size_t rxbuf_len, size_t txbuf_len);
|
||||
|
||||
///** Set baud rate */
|
||||
//void usart_iface_set_baudrate(ComIface *iface, uint32_t baud);
|
||||
@@ -0,0 +1,94 @@
|
||||
#include "display.h"
|
||||
#include "com/debug.h"
|
||||
#include "utils/timebase.h"
|
||||
#include "utils/meanbuf.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#define PIXEL_COUNT 30
|
||||
|
||||
static ws2812_rgb_t pixels[PIXEL_COUNT] = {};
|
||||
|
||||
static MeanBuf *mb;
|
||||
|
||||
void display_show(void)
|
||||
{
|
||||
colorled_set_many((uint32_t*) pixels, PIXEL_COUNT);
|
||||
}
|
||||
|
||||
|
||||
static void handle_sonar_value(float mm)
|
||||
{
|
||||
for (int i = PIXEL_COUNT-1; i > 0; i--) {
|
||||
pixels[i].num = pixels[i-1].num;
|
||||
}
|
||||
|
||||
float x = mm/5.0f;
|
||||
if (x>255) x = 255;
|
||||
|
||||
pixels[0].r = 255-x;
|
||||
pixels[0].b = x;
|
||||
|
||||
display_show();
|
||||
}
|
||||
|
||||
|
||||
static void show(void*arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
handle_sonar_value(meanbuf_current(mb));
|
||||
}
|
||||
|
||||
|
||||
static void sonar(void* arg)
|
||||
{
|
||||
(void)arg;
|
||||
|
||||
info("Sonar");
|
||||
|
||||
GPIOB->BSRR = GPIO_Pin_13;
|
||||
delay_us(10);
|
||||
GPIOB->BRR = GPIO_Pin_13;
|
||||
|
||||
// wait for response
|
||||
|
||||
bool suc = false;
|
||||
until_timeout(50) {
|
||||
if((GPIOB->IDR & (1 << 14)) != 0) {
|
||||
suc = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!suc) {
|
||||
dbg("Not suc");
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t cnt = 0;
|
||||
until_timeout(50) {
|
||||
if((GPIOB->IDR & (1 << 14)) == 0) break;
|
||||
cnt++;
|
||||
}
|
||||
|
||||
float t = cnt / 11.2f;
|
||||
|
||||
meanbuf_add(mb, t);
|
||||
}
|
||||
|
||||
|
||||
void display_init(void)
|
||||
{
|
||||
mb = meanbuf_create(10);
|
||||
|
||||
for (int i = 0; i < PIXEL_COUNT; i++) {
|
||||
pixels[i].num = rgb(0, 0, 255);
|
||||
}
|
||||
|
||||
display_show();
|
||||
|
||||
add_periodic_task(sonar, NULL, 50, true);
|
||||
|
||||
add_periodic_task(show, NULL, 50, true);
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#ifndef DISPLAY_H
|
||||
#define DISPLAY_H
|
||||
|
||||
#include "main.h"
|
||||
#include "colorled.h"
|
||||
|
||||
void display_show(void);
|
||||
|
||||
void display_init(void);
|
||||
|
||||
#endif // DISPLAY_H
|
||||
@@ -0,0 +1,125 @@
|
||||
#include "hw_init.h"
|
||||
|
||||
#include "com/iface_usart.h"
|
||||
#include "com/com_fileio.h"
|
||||
#include "com/datalink.h"
|
||||
|
||||
#include "utils/debounce.h"
|
||||
#include "utils/timebase.h"
|
||||
|
||||
#include "bus/event_queue.h"
|
||||
|
||||
// ---- Private prototypes --------
|
||||
|
||||
static void conf_gpio(void);
|
||||
static void conf_usart(void);
|
||||
static void conf_systick(void);
|
||||
static void conf_subsystems(void);
|
||||
static void conf_irq_prios(void);
|
||||
|
||||
// ---- Public functions ----------
|
||||
|
||||
/**
|
||||
* @brief Initialize hardware resources
|
||||
*/
|
||||
void hw_init(void)
|
||||
{
|
||||
conf_gpio();
|
||||
conf_usart();
|
||||
conf_systick();
|
||||
conf_irq_prios();
|
||||
conf_subsystems();
|
||||
}
|
||||
|
||||
|
||||
// ---- Private functions ---------
|
||||
|
||||
|
||||
|
||||
static void conf_irq_prios(void)
|
||||
{
|
||||
NVIC_SetPriorityGrouping(0); // 0 bits for sub-priority
|
||||
|
||||
// SysTick - highest prio, used for timeouts
|
||||
NVIC_SetPriority(SysTick_IRQn, 0); // SysTick - for timeouts
|
||||
NVIC_SetPriority(USART2_IRQn, 6); // USART - datalink
|
||||
NVIC_SetPriority(USART1_IRQn, 10); // USART - debug
|
||||
|
||||
// FIXME check , probably bad ports
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Configure SW subsystems
|
||||
*/
|
||||
static void conf_subsystems(void)
|
||||
{
|
||||
// task scheduler subsystem
|
||||
timebase_init(15, 15);
|
||||
|
||||
// event and task queues
|
||||
queues_init(15, 15);
|
||||
|
||||
// initialize SBMP for ESP8266
|
||||
dlnk_init();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Configure GPIOs
|
||||
*/
|
||||
static void conf_gpio(void)
|
||||
{
|
||||
GPIO_InitTypeDef gpio_cnf;
|
||||
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
|
||||
|
||||
// Red LED
|
||||
gpio_cnf.GPIO_Pin = GPIO_Pin_13;
|
||||
gpio_cnf.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
gpio_cnf.GPIO_Speed = GPIO_Speed_10MHz;
|
||||
GPIO_Init(GPIOC, &gpio_cnf);
|
||||
|
||||
// colorled | sonar trig
|
||||
gpio_cnf.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13;
|
||||
gpio_cnf.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
gpio_cnf.GPIO_Speed = GPIO_Speed_10MHz;
|
||||
GPIO_Init(GPIOB, &gpio_cnf);
|
||||
|
||||
gpio_cnf.GPIO_Pin = GPIO_Pin_14;
|
||||
gpio_cnf.GPIO_Mode = GPIO_Mode_IPD;
|
||||
gpio_cnf.GPIO_Speed = GPIO_Speed_10MHz;
|
||||
GPIO_Init(GPIOB, &gpio_cnf);
|
||||
|
||||
// A0-sonar trig | UART2 - debug, UART1 - esp
|
||||
gpio_cnf.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_9 | GPIO_Pin_10;
|
||||
gpio_cnf.GPIO_Mode = GPIO_Mode_AF_PP;
|
||||
GPIO_Init(GPIOA, &gpio_cnf);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Configure USARTs
|
||||
*/
|
||||
static void conf_usart(void)
|
||||
{
|
||||
// Debug interface, working as stdout/stderr.
|
||||
debug_iface = usart_iface_init(USART2, 115200, 256, 256);
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
debug_iface->file = stdout;
|
||||
|
||||
// Datalink iface
|
||||
data_iface = usart_iface_init(USART1, 460800, 256, 256);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Configure 1 kHz SysTick w/ interrupt
|
||||
*/
|
||||
static void conf_systick(void)
|
||||
{
|
||||
SysTick_Config(F_CPU / 1000);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "main.h"
|
||||
|
||||
void hw_init(void);
|
||||
|
||||
+57
-13
@@ -1,25 +1,69 @@
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f10x.h"
|
||||
#include <stdio.h>
|
||||
#include "main.h"
|
||||
#include "hw_init.h"
|
||||
|
||||
#include "com/debug.h"
|
||||
#include "com/com_fileio.h"
|
||||
#include "com/com_iface.h"
|
||||
#include "bus/event_queue.h"
|
||||
#include "bus/event_handler.h"
|
||||
#include "utils/timebase.h"
|
||||
|
||||
#include "colorled.h"
|
||||
#include "display.h"
|
||||
#include <math.h>
|
||||
#include <sbmp.h>
|
||||
|
||||
void poll_subsystems(void)
|
||||
{
|
||||
// poll serial buffers (runs callback)
|
||||
com_poll(debug_iface);
|
||||
com_poll(data_iface);
|
||||
|
||||
// run queued tasks
|
||||
tq_poll();
|
||||
|
||||
// handle queued events
|
||||
Event evt;
|
||||
|
||||
until_timeout(2) { // take 2 ms max
|
||||
if (eq_take(&evt)) {
|
||||
run_event_handler(&evt);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void blinky(void* arg)
|
||||
{
|
||||
(void)arg;
|
||||
GPIOC->ODR ^= 1<<13;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
|
||||
hw_init();
|
||||
display_init();
|
||||
|
||||
GPIO_InitTypeDef gpio_cnf;
|
||||
gpio_cnf.GPIO_Pin = GPIO_Pin_13;
|
||||
gpio_cnf.GPIO_Mode = GPIO_Mode_Out_PP;
|
||||
gpio_cnf.GPIO_Speed = GPIO_Speed_2MHz;
|
||||
banner("*** STM32F103K8T6 RGB LED demo ***");
|
||||
banner_info("(c) Ondrej Hruska, 2016");
|
||||
banner_info("Katedra mereni K338, CVUT FEL");
|
||||
|
||||
GPIO_Init(GPIOC, &gpio_cnf);
|
||||
|
||||
add_periodic_task(blinky, NULL, 500, false);
|
||||
|
||||
while (1) {
|
||||
GPIOC->ODR ^= GPIO_Pin_13;
|
||||
|
||||
// delay
|
||||
for (int i = 0; i < 1000000; i++);
|
||||
poll_subsystems();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void dlnk_rx(SBMP_Datagram *dg)
|
||||
{
|
||||
dbg("Rx dg type %d", dg->type);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#ifndef MAIN_H
|
||||
#define MAIN_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <stm32f10x.h>
|
||||
|
||||
#define MIN(a,b) ((a)>(b)?(b):(a))
|
||||
#define MAX(a,b) ((a)<(b)?(b):(a))
|
||||
#define STR_HELPER(x) #x
|
||||
#define STR(x) STR_HELPER(x)
|
||||
|
||||
#endif // MAIN_H
|
||||
@@ -0,0 +1,40 @@
|
||||
#include "com/debug.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
static void reset_when_done(void)
|
||||
{
|
||||
for (uint32_t i = 0; i < 20000; i++) {
|
||||
if (com_tx_done(debug_iface)) break;
|
||||
}
|
||||
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
|
||||
void *malloc_safe_do(size_t size, const char* file, uint32_t line)
|
||||
{
|
||||
void *mem = malloc(size);
|
||||
if (mem == NULL) {
|
||||
// malloc failed
|
||||
error("Malloc failed in file %s on line %"PRIu32, file, line);
|
||||
reset_when_done();
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
|
||||
void *calloc_safe_do(size_t nmemb, size_t size, const char* file, uint32_t line)
|
||||
{
|
||||
void *mem = calloc(size, nmemb);
|
||||
if (mem == NULL) {
|
||||
// malloc failed
|
||||
error("Malloc failed in file %s on line %"PRIu32, file, line);
|
||||
reset_when_done();
|
||||
}
|
||||
|
||||
return mem;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef MALLOC_SAFE_H
|
||||
#define MALLOC_SAFE_H
|
||||
|
||||
/**
|
||||
* Malloc that prints error and restarts the system on failure.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
void *malloc_safe_do(size_t size, const char* file, uint32_t line);
|
||||
void *calloc_safe_do(size_t nmemb, size_t size, const char* file, uint32_t line);
|
||||
|
||||
#define malloc_s(size) malloc_safe_do(size, __FILE__, __LINE__)
|
||||
#define calloc_s(nmemb, size) calloc_safe_do(nmemb, size, __FILE__, __LINE__)
|
||||
|
||||
#endif // MALLOC_SAFE_H
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "main.h"
|
||||
#include "utils/timebase.h"
|
||||
#include "com/debug.h"
|
||||
|
||||
#ifdef USE_FULL_ASSERT
|
||||
|
||||
/**
|
||||
* @brief Reports the name of the source file and the source line number
|
||||
* where the assert_param error has occurred.
|
||||
* @param file: pointer to the source file name
|
||||
* @param line: assert_param error line source number
|
||||
* @return None
|
||||
*/
|
||||
void __attribute__((noreturn))
|
||||
assert_failed(uint8_t* file, uint32_t line)
|
||||
{
|
||||
error("Assert failed in file %s, line %"PRIu32".", file, line);
|
||||
|
||||
/* Infinite loop */
|
||||
while (1);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "stm32f10x_it.h"
|
||||
#include "utils/timebase.h"
|
||||
|
||||
/** @addtogroup STM32F10x_StdPeriph_Template
|
||||
* @{
|
||||
@@ -138,6 +139,7 @@ void PendSV_Handler(void)
|
||||
*/
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
timebase_ms_cb();
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
register char * stack_ptr asm("sp");
|
||||
|
||||
caddr_t _sbrk(int incr)
|
||||
{
|
||||
extern char end __asm("end");
|
||||
static char *heap_end;
|
||||
char *prev_heap_end;
|
||||
|
||||
if (heap_end == 0)
|
||||
heap_end = &end;
|
||||
|
||||
prev_heap_end = heap_end;
|
||||
if (heap_end + incr > stack_ptr)
|
||||
{
|
||||
// write(1, "Heap and stack collision\n", 25);
|
||||
// abort();
|
||||
errno = ENOMEM;
|
||||
return (caddr_t) -1;
|
||||
}
|
||||
|
||||
heap_end += incr;
|
||||
|
||||
return (caddr_t) prev_heap_end;
|
||||
}
|
||||
|
||||
|
||||
// Other systcalls are defined in
|
||||
// - com/com_fileio.c
|
||||
// - hw_utils/reset.h
|
||||
+108
-175
@@ -105,7 +105,7 @@
|
||||
|
||||
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
|
||||
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
|
||||
#define SYSCLK_FREQ_24MHz 24000000
|
||||
#define SYSCLK_FREQ_24MHz 24000000
|
||||
#else
|
||||
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
|
||||
/* #define SYSCLK_FREQ_24MHz 24000000 */
|
||||
@@ -149,22 +149,22 @@
|
||||
* Clock Definitions
|
||||
*******************************************************************************/
|
||||
#ifdef SYSCLK_FREQ_HSE
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /*!< System Clock Frequency (Core Clock) */
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /*!< System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_24MHz
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz; /*!< System Clock Frequency (Core Clock) */
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz; /*!< System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_36MHz
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_36MHz; /*!< System Clock Frequency (Core Clock) */
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_36MHz; /*!< System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_48MHz
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz; /*!< System Clock Frequency (Core Clock) */
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz; /*!< System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_56MHz
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz; /*!< System Clock Frequency (Core Clock) */
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz; /*!< System Clock Frequency (Core Clock) */
|
||||
#elif defined SYSCLK_FREQ_72MHz
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /*!< System Clock Frequency (Core Clock) */
|
||||
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /*!< System Clock Frequency (Core Clock) */
|
||||
#else /*!< HSI Selected as System Clock source */
|
||||
uint32_t SystemCoreClock = HSI_VALUE; /*!< System Clock Frequency (Core Clock) */
|
||||
uint32_t SystemCoreClock = HSI_VALUE; /*!< System Clock Frequency (Core Clock) */
|
||||
#endif
|
||||
|
||||
__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
|
||||
static __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
@@ -176,21 +176,21 @@ __I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}
|
||||
static void SetSysClock(void);
|
||||
|
||||
#ifdef SYSCLK_FREQ_HSE
|
||||
static void SetSysClockToHSE(void);
|
||||
static void SetSysClockToHSE(void);
|
||||
#elif defined SYSCLK_FREQ_24MHz
|
||||
static void SetSysClockTo24(void);
|
||||
static void SetSysClockTo24(void);
|
||||
#elif defined SYSCLK_FREQ_36MHz
|
||||
static void SetSysClockTo36(void);
|
||||
static void SetSysClockTo36(void);
|
||||
#elif defined SYSCLK_FREQ_48MHz
|
||||
static void SetSysClockTo48(void);
|
||||
static void SetSysClockTo48(void);
|
||||
#elif defined SYSCLK_FREQ_56MHz
|
||||
static void SetSysClockTo56(void);
|
||||
static void SetSysClockTo56(void);
|
||||
#elif defined SYSCLK_FREQ_72MHz
|
||||
static void SetSysClockTo72(void);
|
||||
static void SetSysClockTo72(void);
|
||||
#endif
|
||||
|
||||
#ifdef DATA_IN_ExtSRAM
|
||||
static void SystemInit_ExtMemCtl(void);
|
||||
static void SystemInit_ExtMemCtl(void);
|
||||
#endif /* DATA_IN_ExtSRAM */
|
||||
|
||||
/**
|
||||
@@ -209,7 +209,7 @@ static void SetSysClock(void);
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemInit (void)
|
||||
void SystemInit(void)
|
||||
{
|
||||
/* Reset the RCC clock configuration to the default reset state(for debug purpose) */
|
||||
/* Set HSION bit */
|
||||
@@ -252,9 +252,9 @@ void SystemInit (void)
|
||||
#endif /* STM32F10X_CL */
|
||||
|
||||
#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
|
||||
#ifdef DATA_IN_ExtSRAM
|
||||
#ifdef DATA_IN_ExtSRAM
|
||||
SystemInit_ExtMemCtl();
|
||||
#endif /* DATA_IN_ExtSRAM */
|
||||
#endif /* DATA_IN_ExtSRAM */
|
||||
#endif
|
||||
|
||||
/* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
|
||||
@@ -303,7 +303,7 @@ void SystemInit (void)
|
||||
* @param None
|
||||
* @retval None
|
||||
*/
|
||||
void SystemCoreClockUpdate (void)
|
||||
void SystemCoreClockUpdate(void)
|
||||
{
|
||||
uint32_t tmp = 0, pllmull = 0, pllsource = 0;
|
||||
|
||||
@@ -318,8 +318,7 @@ void SystemCoreClockUpdate (void)
|
||||
/* Get SYSCLK source -------------------------------------------------------*/
|
||||
tmp = RCC->CFGR & RCC_CFGR_SWS;
|
||||
|
||||
switch (tmp)
|
||||
{
|
||||
switch (tmp) {
|
||||
case 0x00: /* HSI used as system clock */
|
||||
SystemCoreClock = HSI_VALUE;
|
||||
break;
|
||||
@@ -333,66 +332,55 @@ void SystemCoreClockUpdate (void)
|
||||
pllsource = RCC->CFGR & RCC_CFGR_PLLSRC;
|
||||
|
||||
#ifndef STM32F10X_CL
|
||||
pllmull = ( pllmull >> 18) + 2;
|
||||
pllmull = (pllmull >> 18) + 2;
|
||||
|
||||
if (pllsource == 0x00)
|
||||
{
|
||||
if (pllsource == 0x00) {
|
||||
/* HSI oscillator clock divided by 2 selected as PLL clock entry */
|
||||
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
|
||||
} else {
|
||||
#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
|
||||
prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1;
|
||||
/* HSE oscillator clock selected as PREDIV1 clock entry */
|
||||
SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
|
||||
#else
|
||||
#else
|
||||
/* HSE selected as PLL clock entry */
|
||||
if ((RCC->CFGR & RCC_CFGR_PLLXTPRE) != (uint32_t)RESET)
|
||||
{/* HSE oscillator clock divided by 2 */
|
||||
if ((RCC->CFGR & RCC_CFGR_PLLXTPRE) != (uint32_t)RESET) {
|
||||
/* HSE oscillator clock divided by 2 */
|
||||
SystemCoreClock = (HSE_VALUE >> 1) * pllmull;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
SystemCoreClock = HSE_VALUE * pllmull;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
pllmull = pllmull >> 18;
|
||||
|
||||
if (pllmull != 0x0D)
|
||||
{
|
||||
if (pllmull != 0x0D) {
|
||||
pllmull += 2;
|
||||
}
|
||||
else
|
||||
{ /* PLL multiplication factor = PLL input clock * 6.5 */
|
||||
} else {
|
||||
/* PLL multiplication factor = PLL input clock * 6.5 */
|
||||
pllmull = 13 / 2;
|
||||
}
|
||||
|
||||
if (pllsource == 0x00)
|
||||
{
|
||||
if (pllsource == 0x00) {
|
||||
/* HSI oscillator clock divided by 2 selected as PLL clock entry */
|
||||
SystemCoreClock = (HSI_VALUE >> 1) * pllmull;
|
||||
}
|
||||
else
|
||||
{/* PREDIV1 selected as PLL clock entry */
|
||||
} else {
|
||||
/* PREDIV1 selected as PLL clock entry */
|
||||
|
||||
/* Get PREDIV1 clock source and division factor */
|
||||
prediv1source = RCC->CFGR2 & RCC_CFGR2_PREDIV1SRC;
|
||||
prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1;
|
||||
|
||||
if (prediv1source == 0)
|
||||
{
|
||||
if (prediv1source == 0) {
|
||||
/* HSE oscillator clock selected as PREDIV1 clock entry */
|
||||
SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull;
|
||||
}
|
||||
else
|
||||
{/* PLL2 clock selected as PREDIV1 clock entry */
|
||||
} else {
|
||||
/* PLL2 clock selected as PREDIV1 clock entry */
|
||||
|
||||
/* Get PREDIV2 division factor and PLL2 multiplication factor */
|
||||
prediv2factor = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> 4) + 1;
|
||||
pll2mull = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> 8 ) + 2;
|
||||
pll2mull = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> 8) + 2;
|
||||
SystemCoreClock = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull;
|
||||
}
|
||||
}
|
||||
@@ -454,7 +442,7 @@ static void SetSysClock(void)
|
||||
*/
|
||||
void SystemInit_ExtMemCtl(void)
|
||||
{
|
||||
/*!< FSMC Bank1 NOR/SRAM3 is used for the STM3210E-EVAL, if another Bank is
|
||||
/*!< FSMC Bank1 NOR/SRAM3 is used for the STM3210E-EVAL, if another Bank is
|
||||
required, then adjust the Register Addresses */
|
||||
|
||||
/* Enable FSMC clock */
|
||||
@@ -463,11 +451,11 @@ void SystemInit_ExtMemCtl(void)
|
||||
/* Enable GPIOD, GPIOE, GPIOF and GPIOG clocks */
|
||||
RCC->APB2ENR = 0x000001E0;
|
||||
|
||||
/* --------------- SRAM Data lines, NOE and NWE configuration ---------------*/
|
||||
/*---------------- SRAM Address lines configuration -------------------------*/
|
||||
/*---------------- NOE and NWE configuration --------------------------------*/
|
||||
/*---------------- NE3 configuration ----------------------------------------*/
|
||||
/*---------------- NBL0, NBL1 configuration ---------------------------------*/
|
||||
/* --------------- SRAM Data lines, NOE and NWE configuration ---------------*/
|
||||
/*---------------- SRAM Address lines configuration -------------------------*/
|
||||
/*---------------- NOE and NWE configuration --------------------------------*/
|
||||
/*---------------- NE3 configuration ----------------------------------------*/
|
||||
/*---------------- NBL0, NBL1 configuration ---------------------------------*/
|
||||
|
||||
GPIOD->CRL = 0x44BB44BB;
|
||||
GPIOD->CRH = 0xBBBBBBBB;
|
||||
@@ -481,8 +469,8 @@ void SystemInit_ExtMemCtl(void)
|
||||
GPIOG->CRL = 0x44BBBBBB;
|
||||
GPIOG->CRH = 0x44444B44;
|
||||
|
||||
/*---------------- FSMC Configuration ---------------------------------------*/
|
||||
/*---------------- Enable FSMC Bank1_SRAM Bank ------------------------------*/
|
||||
/*---------------- FSMC Configuration ---------------------------------------*/
|
||||
/*---------------- Enable FSMC Bank1_SRAM Bank ------------------------------*/
|
||||
|
||||
FSMC_Bank1->BTCR[4] = 0x00001011;
|
||||
FSMC_Bank1->BTCR[5] = 0x00000200;
|
||||
@@ -506,23 +494,18 @@ static void SetSysClockToHSE(void)
|
||||
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
|
||||
|
||||
/* Wait till HSE is ready and if Time out is reached exit */
|
||||
do
|
||||
{
|
||||
do {
|
||||
HSEStatus = RCC->CR & RCC_CR_HSERDY;
|
||||
StartUpCounter++;
|
||||
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
} while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
|
||||
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
|
||||
{
|
||||
if ((RCC->CR & RCC_CR_HSERDY) != RESET) {
|
||||
HSEStatus = (uint32_t)0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
HSEStatus = (uint32_t)0x00;
|
||||
}
|
||||
|
||||
if (HSEStatus == (uint32_t)0x01)
|
||||
{
|
||||
if (HSEStatus == (uint32_t)0x01) {
|
||||
|
||||
#if !defined STM32F10X_LD_VL && !defined STM32F10X_MD_VL && !defined STM32F10X_HD_VL
|
||||
/* Enable Prefetch Buffer */
|
||||
@@ -534,12 +517,9 @@ static void SetSysClockToHSE(void)
|
||||
#ifndef STM32F10X_CL
|
||||
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0;
|
||||
#else
|
||||
if (HSE_VALUE <= 24000000)
|
||||
{
|
||||
if (HSE_VALUE <= 24000000) {
|
||||
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1;
|
||||
}
|
||||
#endif /* STM32F10X_CL */
|
||||
@@ -559,12 +539,10 @@ static void SetSysClockToHSE(void)
|
||||
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_HSE;
|
||||
|
||||
/* Wait till HSE is used as system clock source */
|
||||
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x04)
|
||||
{
|
||||
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x04) {
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* If HSE fails to start-up, the application will have wrong clock
|
||||
} else {
|
||||
/* If HSE fails to start-up, the application will have wrong clock
|
||||
configuration. User can add here some code to deal with this error */
|
||||
}
|
||||
}
|
||||
@@ -585,23 +563,18 @@ static void SetSysClockTo24(void)
|
||||
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
|
||||
|
||||
/* Wait till HSE is ready and if Time out is reached exit */
|
||||
do
|
||||
{
|
||||
do {
|
||||
HSEStatus = RCC->CR & RCC_CR_HSERDY;
|
||||
StartUpCounter++;
|
||||
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
} while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
|
||||
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
|
||||
{
|
||||
if ((RCC->CR & RCC_CR_HSERDY) != RESET) {
|
||||
HSEStatus = (uint32_t)0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
HSEStatus = (uint32_t)0x00;
|
||||
}
|
||||
|
||||
if (HSEStatus == (uint32_t)0x01)
|
||||
{
|
||||
if (HSEStatus == (uint32_t)0x01) {
|
||||
#if !defined STM32F10X_LD_VL && !defined STM32F10X_MD_VL && !defined STM32F10X_HD_VL
|
||||
/* Enable Prefetch Buffer */
|
||||
FLASH->ACR |= FLASH_ACR_PRFTBE;
|
||||
@@ -637,8 +610,7 @@ static void SetSysClockTo24(void)
|
||||
/* Enable PLL2 */
|
||||
RCC->CR |= RCC_CR_PLL2ON;
|
||||
/* Wait till PLL2 is ready */
|
||||
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
|
||||
{
|
||||
while ((RCC->CR & RCC_CR_PLL2RDY) == 0) {
|
||||
}
|
||||
#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
|
||||
/* PLL configuration: = (HSE / 2) * 6 = 24 MHz */
|
||||
@@ -654,8 +626,7 @@ static void SetSysClockTo24(void)
|
||||
RCC->CR |= RCC_CR_PLLON;
|
||||
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CR & RCC_CR_PLLRDY) == 0)
|
||||
{
|
||||
while ((RCC->CR & RCC_CR_PLLRDY) == 0) {
|
||||
}
|
||||
|
||||
/* Select PLL as system clock source */
|
||||
@@ -663,12 +634,10 @@ static void SetSysClockTo24(void)
|
||||
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
|
||||
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) {
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* If HSE fails to start-up, the application will have wrong clock
|
||||
} else {
|
||||
/* If HSE fails to start-up, the application will have wrong clock
|
||||
configuration. User can add here some code to deal with this error */
|
||||
}
|
||||
}
|
||||
@@ -689,23 +658,18 @@ static void SetSysClockTo36(void)
|
||||
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
|
||||
|
||||
/* Wait till HSE is ready and if Time out is reached exit */
|
||||
do
|
||||
{
|
||||
do {
|
||||
HSEStatus = RCC->CR & RCC_CR_HSERDY;
|
||||
StartUpCounter++;
|
||||
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
} while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
|
||||
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
|
||||
{
|
||||
if ((RCC->CR & RCC_CR_HSERDY) != RESET) {
|
||||
HSEStatus = (uint32_t)0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
HSEStatus = (uint32_t)0x00;
|
||||
}
|
||||
|
||||
if (HSEStatus == (uint32_t)0x01)
|
||||
{
|
||||
if (HSEStatus == (uint32_t)0x01) {
|
||||
/* Enable Prefetch Buffer */
|
||||
FLASH->ACR |= FLASH_ACR_PRFTBE;
|
||||
|
||||
@@ -741,8 +705,7 @@ static void SetSysClockTo36(void)
|
||||
/* Enable PLL2 */
|
||||
RCC->CR |= RCC_CR_PLL2ON;
|
||||
/* Wait till PLL2 is ready */
|
||||
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
|
||||
{
|
||||
while ((RCC->CR & RCC_CR_PLL2RDY) == 0) {
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -755,8 +718,7 @@ static void SetSysClockTo36(void)
|
||||
RCC->CR |= RCC_CR_PLLON;
|
||||
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CR & RCC_CR_PLLRDY) == 0)
|
||||
{
|
||||
while ((RCC->CR & RCC_CR_PLLRDY) == 0) {
|
||||
}
|
||||
|
||||
/* Select PLL as system clock source */
|
||||
@@ -764,12 +726,10 @@ static void SetSysClockTo36(void)
|
||||
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
|
||||
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) {
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* If HSE fails to start-up, the application will have wrong clock
|
||||
} else {
|
||||
/* If HSE fails to start-up, the application will have wrong clock
|
||||
configuration. User can add here some code to deal with this error */
|
||||
}
|
||||
}
|
||||
@@ -790,23 +750,18 @@ static void SetSysClockTo48(void)
|
||||
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
|
||||
|
||||
/* Wait till HSE is ready and if Time out is reached exit */
|
||||
do
|
||||
{
|
||||
do {
|
||||
HSEStatus = RCC->CR & RCC_CR_HSERDY;
|
||||
StartUpCounter++;
|
||||
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
} while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
|
||||
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
|
||||
{
|
||||
if ((RCC->CR & RCC_CR_HSERDY) != RESET) {
|
||||
HSEStatus = (uint32_t)0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
HSEStatus = (uint32_t)0x00;
|
||||
}
|
||||
|
||||
if (HSEStatus == (uint32_t)0x01)
|
||||
{
|
||||
if (HSEStatus == (uint32_t)0x01) {
|
||||
/* Enable Prefetch Buffer */
|
||||
FLASH->ACR |= FLASH_ACR_PRFTBE;
|
||||
|
||||
@@ -836,8 +791,7 @@ static void SetSysClockTo48(void)
|
||||
/* Enable PLL2 */
|
||||
RCC->CR |= RCC_CR_PLL2ON;
|
||||
/* Wait till PLL2 is ready */
|
||||
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
|
||||
{
|
||||
while ((RCC->CR & RCC_CR_PLL2RDY) == 0) {
|
||||
}
|
||||
|
||||
|
||||
@@ -855,8 +809,7 @@ static void SetSysClockTo48(void)
|
||||
RCC->CR |= RCC_CR_PLLON;
|
||||
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CR & RCC_CR_PLLRDY) == 0)
|
||||
{
|
||||
while ((RCC->CR & RCC_CR_PLLRDY) == 0) {
|
||||
}
|
||||
|
||||
/* Select PLL as system clock source */
|
||||
@@ -864,12 +817,10 @@ static void SetSysClockTo48(void)
|
||||
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
|
||||
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) {
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* If HSE fails to start-up, the application will have wrong clock
|
||||
} else {
|
||||
/* If HSE fails to start-up, the application will have wrong clock
|
||||
configuration. User can add here some code to deal with this error */
|
||||
}
|
||||
}
|
||||
@@ -891,23 +842,18 @@ static void SetSysClockTo56(void)
|
||||
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
|
||||
|
||||
/* Wait till HSE is ready and if Time out is reached exit */
|
||||
do
|
||||
{
|
||||
do {
|
||||
HSEStatus = RCC->CR & RCC_CR_HSERDY;
|
||||
StartUpCounter++;
|
||||
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
} while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
|
||||
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
|
||||
{
|
||||
if ((RCC->CR & RCC_CR_HSERDY) != RESET) {
|
||||
HSEStatus = (uint32_t)0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
HSEStatus = (uint32_t)0x00;
|
||||
}
|
||||
|
||||
if (HSEStatus == (uint32_t)0x01)
|
||||
{
|
||||
if (HSEStatus == (uint32_t)0x01) {
|
||||
/* Enable Prefetch Buffer */
|
||||
FLASH->ACR |= FLASH_ACR_PRFTBE;
|
||||
|
||||
@@ -937,8 +883,7 @@ static void SetSysClockTo56(void)
|
||||
/* Enable PLL2 */
|
||||
RCC->CR |= RCC_CR_PLL2ON;
|
||||
/* Wait till PLL2 is ready */
|
||||
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
|
||||
{
|
||||
while ((RCC->CR & RCC_CR_PLL2RDY) == 0) {
|
||||
}
|
||||
|
||||
|
||||
@@ -957,8 +902,7 @@ static void SetSysClockTo56(void)
|
||||
RCC->CR |= RCC_CR_PLLON;
|
||||
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CR & RCC_CR_PLLRDY) == 0)
|
||||
{
|
||||
while ((RCC->CR & RCC_CR_PLLRDY) == 0) {
|
||||
}
|
||||
|
||||
/* Select PLL as system clock source */
|
||||
@@ -966,12 +910,10 @@ static void SetSysClockTo56(void)
|
||||
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
|
||||
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) {
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* If HSE fails to start-up, the application will have wrong clock
|
||||
} else {
|
||||
/* If HSE fails to start-up, the application will have wrong clock
|
||||
configuration. User can add here some code to deal with this error */
|
||||
}
|
||||
}
|
||||
@@ -993,23 +935,18 @@ static void SetSysClockTo72(void)
|
||||
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
|
||||
|
||||
/* Wait till HSE is ready and if Time out is reached exit */
|
||||
do
|
||||
{
|
||||
do {
|
||||
HSEStatus = RCC->CR & RCC_CR_HSERDY;
|
||||
StartUpCounter++;
|
||||
} while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
} while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
|
||||
|
||||
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
|
||||
{
|
||||
if ((RCC->CR & RCC_CR_HSERDY) != RESET) {
|
||||
HSEStatus = (uint32_t)0x01;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
HSEStatus = (uint32_t)0x00;
|
||||
}
|
||||
|
||||
if (HSEStatus == (uint32_t)0x01)
|
||||
{
|
||||
if (HSEStatus == (uint32_t)0x01) {
|
||||
/* Enable Prefetch Buffer */
|
||||
FLASH->ACR |= FLASH_ACR_PRFTBE;
|
||||
|
||||
@@ -1040,8 +977,7 @@ static void SetSysClockTo72(void)
|
||||
/* Enable PLL2 */
|
||||
RCC->CR |= RCC_CR_PLL2ON;
|
||||
/* Wait till PLL2 is ready */
|
||||
while((RCC->CR & RCC_CR_PLL2RDY) == 0)
|
||||
{
|
||||
while ((RCC->CR & RCC_CR_PLL2RDY) == 0) {
|
||||
}
|
||||
|
||||
|
||||
@@ -1060,8 +996,7 @@ static void SetSysClockTo72(void)
|
||||
RCC->CR |= RCC_CR_PLLON;
|
||||
|
||||
/* Wait till PLL is ready */
|
||||
while((RCC->CR & RCC_CR_PLLRDY) == 0)
|
||||
{
|
||||
while ((RCC->CR & RCC_CR_PLLRDY) == 0) {
|
||||
}
|
||||
|
||||
/* Select PLL as system clock source */
|
||||
@@ -1069,12 +1004,10 @@ static void SetSysClockTo72(void)
|
||||
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
|
||||
|
||||
/* Wait till PLL is used as system clock source */
|
||||
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
|
||||
{
|
||||
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) {
|
||||
}
|
||||
}
|
||||
else
|
||||
{ /* If HSE fails to start-up, the application will have wrong clock
|
||||
} else {
|
||||
/* If HSE fails to start-up, the application will have wrong clock
|
||||
configuration. User can add here some code to deal with this error */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "circbuf.h"
|
||||
#include "malloc_safe.h"
|
||||
|
||||
// --- Circbuf data structure ----
|
||||
|
||||
/** Offset in void* buffer */
|
||||
#define PV_OFFS(pvBuf, elem_size, index) ((uint8_t*)(pvBuf) + ((elem_size)*(index)))
|
||||
|
||||
|
||||
// Instance structure
|
||||
struct circbuf_struct {
|
||||
void *buf;
|
||||
size_t elem_size;
|
||||
size_t cap;
|
||||
size_t lr; // last read pos
|
||||
size_t nw; // next write pos
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @brief Write data to a CircBuf slot
|
||||
* @param cb : circbuf
|
||||
* @param index : slot index
|
||||
* @param source : data source
|
||||
*/
|
||||
static void write_buffer(CircBuf *cb, size_t index, const void *source)
|
||||
{
|
||||
memcpy(PV_OFFS(cb->buf, cb->elem_size, index), source, cb->elem_size);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Copy data from a CircBuf slot to a buffer
|
||||
* @param cb : circbuf
|
||||
* @param index : slot index
|
||||
* @param dest : destination buffer
|
||||
*/
|
||||
static void read_buffer(const CircBuf *cb, size_t index, void *dest)
|
||||
{
|
||||
memcpy(dest, PV_OFFS(cb->buf, cb->elem_size, index), cb->elem_size);
|
||||
}
|
||||
|
||||
|
||||
/** Create a cbuf */
|
||||
CircBuf *cbuf_create(size_t capacity, size_t elem_size)
|
||||
{
|
||||
// add one, because one is always unused.
|
||||
capacity++;
|
||||
|
||||
// Allocate the structure
|
||||
CircBuf *cb = malloc_s(sizeof(CircBuf));
|
||||
|
||||
// allocate the buffer
|
||||
cb->buf = malloc_s(capacity * elem_size);
|
||||
|
||||
// set capacity, clear state
|
||||
cb->elem_size = elem_size;
|
||||
cb->cap = capacity;
|
||||
cbuf_clear(cb);
|
||||
|
||||
return cb;
|
||||
}
|
||||
|
||||
|
||||
/** Release cbuf memory */
|
||||
void cbuf_destroy(CircBuf *cb)
|
||||
{
|
||||
if (cb != NULL) {
|
||||
if (cb->buf != NULL) {
|
||||
free(cb->buf);
|
||||
}
|
||||
|
||||
free(cb);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Check if cbuf is full */
|
||||
bool cbuf_full(const CircBuf *cb)
|
||||
{
|
||||
if (cb == NULL) return false;
|
||||
|
||||
return (cb->lr == cb->nw);
|
||||
}
|
||||
|
||||
|
||||
/** Check if cbuf is empty */
|
||||
bool cbuf_empty(const CircBuf *cb)
|
||||
{
|
||||
if (cb == NULL) return true;
|
||||
|
||||
return ((cb->lr + 1) % cb->cap) == cb->nw;
|
||||
}
|
||||
|
||||
|
||||
/** Write a byte to the buffer, if space left */
|
||||
bool cbuf_append(CircBuf *cb, const void *source)
|
||||
{
|
||||
if (cb == NULL) return false;
|
||||
if (source == NULL) return false;
|
||||
if (cbuf_full(cb)) return false;
|
||||
|
||||
write_buffer(cb, cb->nw, source);
|
||||
|
||||
// increment
|
||||
cb->nw++;
|
||||
if (cb->nw == cb->cap) cb->nw = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Push value to the end, like a stack. */
|
||||
bool cbuf_push(CircBuf *cb, const void *source)
|
||||
{
|
||||
if (cb == NULL) return false;
|
||||
if (source == NULL) return false;
|
||||
if (cbuf_full(cb)) return false;
|
||||
|
||||
write_buffer(cb, cb->lr, source);
|
||||
|
||||
// move lr back
|
||||
if (cb->lr == 0) {
|
||||
cb->lr = cb->cap - 1; // wrap to the end
|
||||
} else {
|
||||
cb->lr--;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Read one byte, if not empty. */
|
||||
bool cbuf_pop(CircBuf *cb, void *dest)
|
||||
{
|
||||
if (cb == NULL || dest == NULL) return false;
|
||||
if (cbuf_empty(cb)) return false;
|
||||
|
||||
// increment
|
||||
cb->lr++;
|
||||
if (cb->lr == cb->cap) cb->lr = 0;
|
||||
|
||||
read_buffer(cb, cb->lr, dest);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/** Clear a cbuf */
|
||||
void cbuf_clear(CircBuf *cb)
|
||||
{
|
||||
if (cb == NULL) return;
|
||||
|
||||
cb->lr = cb->cap - 1;
|
||||
cb->nw = 0;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @file circbuf.h
|
||||
* @author Ondřej Hruška, 2016
|
||||
*
|
||||
* Circular buffer / queue / stack.
|
||||
* Slots are pre-allocated, values are copied into the buffer.
|
||||
*
|
||||
* The buffer may be used as a stack, event queue or a simple buffer.
|
||||
*
|
||||
* -------------------------------------
|
||||
*
|
||||
* NW LR
|
||||
* append -> [][][][] -> pop
|
||||
* <- push
|
||||
*
|
||||
* NW - next write pointer (stack base)
|
||||
* LR - last read position (stack top)
|
||||
*
|
||||
* -------------------------------------
|
||||
*
|
||||
* MIT license
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
typedef struct circbuf_struct CircBuf;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize a circular buffer. The buffer is malloc'd.
|
||||
* @param capacity : buffer capacity
|
||||
* @param elem_size : size of one element
|
||||
* @return pointer to the buffer instance
|
||||
*/
|
||||
CircBuf *cbuf_create(size_t capacity, size_t elem_size);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Destroy a buffer, freeing used memory.
|
||||
*
|
||||
* @attention
|
||||
* If the buffer items have malloc'd members, you have
|
||||
* to free them manually to avoid a memory leak.
|
||||
*
|
||||
* @param cb : buffer
|
||||
*/
|
||||
void cbuf_destroy(CircBuf *cb);
|
||||
|
||||
|
||||
/** Test for full buffer */
|
||||
bool cbuf_full(const CircBuf *cb);
|
||||
|
||||
|
||||
/** Test for empty buffer */
|
||||
bool cbuf_empty(const CircBuf *cb);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Append a value to the buffer (FIFO)
|
||||
* @param cb : buffer
|
||||
* @param source : pointer to a value (will be copied)
|
||||
* @return success
|
||||
*/
|
||||
bool cbuf_append(CircBuf *cb, const void *source);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Push a value into the circbuf (LIFO).
|
||||
*
|
||||
* @param cb : buffer
|
||||
* @param source : pointer to a value (will be copied)
|
||||
* @return success
|
||||
*/
|
||||
bool cbuf_push(CircBuf *cb, const void *source);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Read a value from the buffer, return susccess.
|
||||
*
|
||||
* @param cb : buffer
|
||||
* @param dest : read destionation. If NULL, value is discarded.
|
||||
* @return success
|
||||
*/
|
||||
bool cbuf_pop(CircBuf *cb, void *dest);
|
||||
|
||||
|
||||
/** @brief Remove all data from buffer */
|
||||
void cbuf_clear(CircBuf *cb);
|
||||
@@ -0,0 +1,171 @@
|
||||
#include "main.h"
|
||||
#include "debounce.h"
|
||||
#include "timebase.h"
|
||||
#include "malloc_safe.h"
|
||||
|
||||
// ms debounce time
|
||||
|
||||
#define DEF_DEBO_TIME 20
|
||||
|
||||
typedef struct {
|
||||
GPIO_TypeDef *GPIOx; ///< GPIO base
|
||||
uint16_t pin; ///< bit mask
|
||||
bool state; ///< current state
|
||||
bool invert; ///< invert pin
|
||||
debo_id_t id; ///< pin ID
|
||||
ms_time_t debo_time; ///< debouncing time (ms)
|
||||
ms_time_t counter_0; ///< counter for falling edge (ms)
|
||||
ms_time_t counter_1; ///< counter for rising edge (ms)
|
||||
void (*falling_cb)(void);
|
||||
void (*rising_cb)(void);
|
||||
} debo_slot_t;
|
||||
|
||||
|
||||
/** Number of allocated slots */
|
||||
static size_t debo_slot_count = 0;
|
||||
|
||||
/** Slots array */
|
||||
static debo_slot_t *debo_slots;
|
||||
|
||||
/** Next free pin ID for make_id() */
|
||||
static debo_id_t next_pin_id = 1;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get a valid free pin ID for a new entry.
|
||||
* @return the ID.
|
||||
*/
|
||||
static debo_id_t make_id(void)
|
||||
{
|
||||
debo_id_t id = next_pin_id++;
|
||||
|
||||
// make sure no task is given PID 0
|
||||
if (next_pin_id == DEBO_PIN_NONE) {
|
||||
next_pin_id++;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
|
||||
/** Init the debouncer */
|
||||
void debounce_init(size_t slot_count)
|
||||
{
|
||||
debo_slots = calloc_s(slot_count, sizeof(debo_slot_t));
|
||||
debo_slot_count = slot_count;
|
||||
}
|
||||
|
||||
|
||||
/** Register a pin */
|
||||
debo_id_t debo_register_pin(debo_init_t *init)
|
||||
{
|
||||
assert_param(IS_GPIO_ALL_PERIPH(init->GPIOx));
|
||||
assert_param(IS_GET_GPIO_PIN(init->pin));
|
||||
|
||||
for (size_t i = 0; i < debo_slot_count; i++) {
|
||||
debo_slot_t *slot = &debo_slots[i];
|
||||
|
||||
if (slot->id != DEBO_PIN_NONE) continue; // slot is used
|
||||
|
||||
slot->GPIOx = init->GPIOx;
|
||||
slot->pin = init->pin;
|
||||
slot->falling_cb = init->falling_cb;
|
||||
slot->rising_cb = init->rising_cb;
|
||||
slot->invert = init->invert;
|
||||
slot->counter_0 = 0;
|
||||
slot->counter_1 = 0;
|
||||
slot->debo_time = (init->debo_time == 0) ? DEF_DEBO_TIME : init->debo_time;
|
||||
|
||||
bool state = GPIO_ReadInputDataBit(slot->GPIOx, slot->pin);
|
||||
if (slot->invert) state = !state;
|
||||
slot->state = state;
|
||||
|
||||
slot->id = make_id();
|
||||
|
||||
return slot->id;
|
||||
}
|
||||
|
||||
return DEBO_PIN_NONE;
|
||||
}
|
||||
|
||||
|
||||
/** Callback that must be called every 1 ms */
|
||||
void debo_periodic_task(void)
|
||||
{
|
||||
for (size_t i = 0; i < debo_slot_count; i++) {
|
||||
debo_slot_t *slot = &debo_slots[i];
|
||||
if (slot->id == DEBO_PIN_NONE) continue; // unused
|
||||
|
||||
bool state = GPIO_ReadInputDataBit(slot->GPIOx, slot->pin);
|
||||
if (slot->invert) state = !state;
|
||||
|
||||
if (slot->state != state) {
|
||||
if (state == 0) {
|
||||
// falling
|
||||
|
||||
if (slot->counter_0++ == slot->debo_time) {
|
||||
slot->state = 0;
|
||||
|
||||
if (slot->falling_cb != NULL) {
|
||||
slot->falling_cb();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// rising
|
||||
|
||||
if (slot->counter_1++ == slot->debo_time) {
|
||||
slot->state = 1;
|
||||
|
||||
if (slot->rising_cb != NULL) {
|
||||
slot->rising_cb();
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// reset counters
|
||||
slot->counter_0 = 0;
|
||||
slot->counter_1 = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check if a pin is high
|
||||
* @param pin_id : Slot ID
|
||||
* @return true if the pin is registered and is HIGH
|
||||
*/
|
||||
bool debo_pin_state(debo_id_t pin_id)
|
||||
{
|
||||
if (pin_id == DEBO_PIN_NONE) return false;
|
||||
|
||||
for (size_t i = 0; i < debo_slot_count; i++) {
|
||||
debo_slot_t *slot = &debo_slots[i];
|
||||
if (slot->id != pin_id) continue;
|
||||
|
||||
return slot->state;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove a pin entry from the debouncer.
|
||||
* @param pin_id : Slot ID
|
||||
* @return true if task found & removed.
|
||||
*/
|
||||
bool debo_remove_pin(debo_id_t pin_id)
|
||||
{
|
||||
if (pin_id == DEBO_PIN_NONE) return false;
|
||||
|
||||
for (size_t i = 0; i < debo_slot_count; i++) {
|
||||
debo_slot_t *slot = &debo_slots[i];
|
||||
if (slot->id != pin_id) continue;
|
||||
|
||||
slot->id = DEBO_PIN_NONE;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
#include "main.h"
|
||||
#include "utils/timebase.h"
|
||||
|
||||
// Debouncer requires that you setup SysTick first.
|
||||
|
||||
/** Debounced pin ID - used for state readout */
|
||||
typedef uint32_t debo_id_t;
|
||||
|
||||
/** debo_id_t indicating unused slot */
|
||||
#define DEBO_PIN_NONE 0
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize the debouncer.
|
||||
*
|
||||
* You have to also register the periodic task to timebase.
|
||||
*
|
||||
* @param pin_count : number of pin slots to allocate
|
||||
*/
|
||||
void debounce_init(size_t pin_count);
|
||||
|
||||
|
||||
/**
|
||||
* @brief 1 ms periodic callback for debouncer. Must be registered to timebase.
|
||||
*/
|
||||
void debo_periodic_task(void);
|
||||
|
||||
|
||||
typedef struct {
|
||||
GPIO_TypeDef *GPIOx; ///< GPIO base
|
||||
uint16_t pin; ///< pin mask
|
||||
ms_time_t debo_time; ///< debounce time in ms, 0 = default (20 ms)
|
||||
bool invert; ///< invert value read from GPIO (button to ground)
|
||||
void (*rising_cb)(void); ///< callback when the pin goes HIGH
|
||||
void (*falling_cb)(void); ///< callback when the pin goes LOW
|
||||
} debo_init_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add a pin for debouncing.
|
||||
*
|
||||
* The pin state will be checked with the configured hysteresis
|
||||
* and callbacks will be called when a state change is detected.
|
||||
*/
|
||||
debo_id_t debo_register_pin(debo_init_t *init_struct);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check if a pin is high
|
||||
* @param pin_id : Slot ID
|
||||
* @return true if the pin is registered and is HIGH
|
||||
*/
|
||||
bool debo_pin_state(debo_id_t pin_id);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Remove a pin entry from the debouncer.
|
||||
* @param pin_id : Slot ID
|
||||
* @return true if task found & removed.
|
||||
*/
|
||||
bool debo_remove_pin(debo_id_t pin_id);
|
||||
@@ -0,0 +1,33 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "matcher.h"
|
||||
|
||||
void matcher_reset(matcher_t *m)
|
||||
{
|
||||
m->cursor = 0;
|
||||
}
|
||||
|
||||
|
||||
/** Handle incoming char. Returns true if this char completed the match. */
|
||||
bool matcher_test(matcher_t * m, uint8_t b)
|
||||
{
|
||||
// If mismatch, rewind (and check at 0)
|
||||
if (m->pattern[m->cursor] != b) {
|
||||
m->cursor = 0;
|
||||
}
|
||||
|
||||
// Check for match
|
||||
if (m->pattern[m->cursor] == b) {
|
||||
// Good char
|
||||
m->cursor++;
|
||||
if (m->pattern[m->cursor] == 0) { // end of pattern
|
||||
m->cursor = 0; // rewind
|
||||
return true; // indicate success
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* @file matcher.h
|
||||
* @author Ondřej Hruška, 2016
|
||||
*
|
||||
* String matching utility.
|
||||
*
|
||||
* Matcher can be used for detecting a pattern in a stream of characters.
|
||||
* With each incoming character, call matcher_test().
|
||||
*
|
||||
* It will return true if the character completed a match.
|
||||
*
|
||||
* MIT license
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct {
|
||||
const char *pattern;
|
||||
size_t cursor;
|
||||
} matcher_t;
|
||||
|
||||
|
||||
/** reset match progress */
|
||||
void matcher_reset(matcher_t *m);
|
||||
|
||||
|
||||
/**
|
||||
* Consume an incoming character.
|
||||
* If this char was the last char of the pattern, returns true and resets matcher.
|
||||
*
|
||||
* If the char is not in the pattern, resets matcher.
|
||||
*
|
||||
* @returns true if the char concluded the expected pattern.
|
||||
*/
|
||||
bool matcher_test(matcher_t * mb, uint8_t b);
|
||||
@@ -0,0 +1,70 @@
|
||||
#include <stdint.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include "meanbuf.h"
|
||||
#include "malloc_safe.h"
|
||||
|
||||
|
||||
struct meanbuf_struct {
|
||||
float * buf; // buffer (allocated at init)
|
||||
size_t cap; // capacity
|
||||
size_t nw; // next write index
|
||||
float mean; // updated on write
|
||||
};
|
||||
|
||||
|
||||
/** Init a buffer */
|
||||
MeanBuf *meanbuf_create(size_t size)
|
||||
{
|
||||
MeanBuf *mb = malloc_s(sizeof(MeanBuf));
|
||||
|
||||
if (size < 1) size = 1;
|
||||
|
||||
mb->buf = calloc_s(size, sizeof(float)); // calloc, so it starts with zeros.
|
||||
mb->cap = size;
|
||||
mb->nw = 0;
|
||||
mb->mean = 0;
|
||||
|
||||
// clean buffer
|
||||
for (uint16_t i = 0; i < size; i++) {
|
||||
mb->buf[i] = 0;
|
||||
}
|
||||
|
||||
return mb;
|
||||
}
|
||||
|
||||
|
||||
void meanbuf_destroy(MeanBuf *mb)
|
||||
{
|
||||
if (mb == NULL) return;
|
||||
|
||||
if (mb->buf != NULL) {
|
||||
free(mb->buf);
|
||||
}
|
||||
|
||||
free(mb);
|
||||
}
|
||||
|
||||
|
||||
/** Add a value to the buffer. Returns current mean. */
|
||||
float meanbuf_add(MeanBuf *mb, float f)
|
||||
{
|
||||
// add sample
|
||||
mb->buf[mb->nw++] = f;
|
||||
if (mb->nw == mb->cap) mb->nw = 0;
|
||||
|
||||
// calculate average
|
||||
float acc = 0;
|
||||
for (size_t i = 0; i < mb->cap; i++) {
|
||||
acc += mb->buf[i];
|
||||
}
|
||||
|
||||
acc /= mb->cap;
|
||||
|
||||
return mb->mean = acc;
|
||||
}
|
||||
|
||||
float meanbuf_current(MeanBuf *mb)
|
||||
{
|
||||
return mb->mean;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* @file meanbuf.h
|
||||
* @author Ondřej Hruška, 2016
|
||||
*
|
||||
* Averaging float buffer. (You can adjust it to use doubles, if you prefer.)
|
||||
*
|
||||
* The meanbuf_create() function allocates a buffer.
|
||||
*
|
||||
* You can then call meanbuf_add() to add a new value into the buffer (and remove the oldest).
|
||||
* This function returns the current average value.
|
||||
*
|
||||
* This buffer can be used for signal smoothing (such as from an analogue sensor).
|
||||
*
|
||||
* MIT license
|
||||
*/
|
||||
|
||||
|
||||
#pragma once
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct meanbuf_struct MeanBuf;
|
||||
|
||||
/** Init a buffer */
|
||||
MeanBuf *meanbuf_create(size_t size);
|
||||
|
||||
/** Deinit a buffer (free buffer array) */
|
||||
void meanbuf_destroy(MeanBuf *mb);
|
||||
|
||||
/** Add a value to the buffer. Returns current mean. */
|
||||
float meanbuf_add(MeanBuf *mb, float f);
|
||||
|
||||
float meanbuf_current(MeanBuf *bm);
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
@@ -0,0 +1,286 @@
|
||||
#include "str_utils.h"
|
||||
#include "matcher.h"
|
||||
#include "malloc_safe.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
// Lot of this stuff is actually not needed anymore,
|
||||
// it was written for the ESP AT firmware, which is no longer used.
|
||||
|
||||
/**
|
||||
* Escape a char.
|
||||
* @returns what to put after backslash, or '\0' for no escape.
|
||||
*/
|
||||
static char escape_char(char c)
|
||||
{
|
||||
switch (c) {
|
||||
case '\r': return 'r';
|
||||
case '\n': return 'n';
|
||||
case '\t': return 't';
|
||||
case '\\': return '\\';
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Escape string in place
|
||||
*/
|
||||
void str_escape_ip(char * buf, size_t buf_len)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
// string length (updated when escapes are performed)
|
||||
size_t slen = strlen(buf);
|
||||
|
||||
for (; i < buf_len - 1 && buf[i] != 0; i++) {
|
||||
char replace = escape_char(buf[i]);
|
||||
|
||||
// Escape, shift trailing chars
|
||||
if (replace != 0) {
|
||||
if (i >= buf_len - 2) {
|
||||
break; // discard the char, escape wouldn't fit.
|
||||
}
|
||||
|
||||
// (could be faster if moved starting at the end)
|
||||
|
||||
char m = buf[i + 1]; // remember next char
|
||||
|
||||
buf[i] = '\\';
|
||||
buf[i + 1] = replace;
|
||||
|
||||
slen++; // account for the added backslash
|
||||
|
||||
// shift trailing chars
|
||||
for (size_t j = i + 2; j <= slen; j++) {
|
||||
char n = buf[j];
|
||||
buf[j] = m;
|
||||
m = n;
|
||||
}
|
||||
|
||||
i++; // skip the insterted slash
|
||||
}
|
||||
}
|
||||
|
||||
buf[i] = 0; // add terminator (in case end of string was reached)
|
||||
}
|
||||
|
||||
|
||||
void str_escape(char *dest, const char *src, size_t dest_len)
|
||||
{
|
||||
size_t di = 0, si = 0;
|
||||
|
||||
for (; src[si] != 0 && di < dest_len - 1; si++) {
|
||||
char orig = src[si];
|
||||
char replace = escape_char(orig);
|
||||
|
||||
if (replace == 0) {
|
||||
dest[di++] = orig;
|
||||
} else {
|
||||
if (di >= dest_len - 2) {
|
||||
break; // out of space
|
||||
}
|
||||
|
||||
dest[di++] = '\\';
|
||||
dest[di++] = replace;
|
||||
}
|
||||
}
|
||||
|
||||
dest[di] = 0; // append terminator
|
||||
}
|
||||
|
||||
|
||||
|
||||
int32_t strpos(const char *haystack, const char *needle)
|
||||
{
|
||||
const char *p = strstr(haystack, needle);
|
||||
if (p) return (p - haystack);
|
||||
return -1; // Not found = -1.
|
||||
}
|
||||
|
||||
|
||||
int32_t strpos_upto(const char *haystack, const char *needle, size_t limit)
|
||||
{
|
||||
if (limit <= 0) return strpos(haystack, needle);
|
||||
|
||||
matcher_t m = {needle, 0};
|
||||
char c;
|
||||
|
||||
for (size_t i = 0; i < limit; i++, haystack++) {
|
||||
c = *haystack;
|
||||
if (c == 0) break;
|
||||
|
||||
if (matcher_test(&m, (uint8_t)c)) {
|
||||
return i - strlen(needle) + 1; // match occured on the last needle char
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int32_t strpos_upto_match(const char *haystack, const char *needle, const char *endmatch)
|
||||
{
|
||||
if (endmatch == NULL) return strpos(haystack, needle);
|
||||
|
||||
matcher_t matcher_needle = {needle, 0};
|
||||
matcher_t matcher_end = {endmatch, 0};
|
||||
char c;
|
||||
|
||||
for (int i = 0;; i++, haystack++) {
|
||||
c = *haystack;
|
||||
if (c == 0) break;
|
||||
|
||||
// match
|
||||
if (matcher_test(&matcher_needle, (uint8_t)c)) {
|
||||
return i - strlen(needle) + 1; // match occured on the last needle char
|
||||
}
|
||||
|
||||
// end
|
||||
if (matcher_test(&matcher_end, (uint8_t)c)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t str_copy(char * dest, const char *src)
|
||||
{
|
||||
char c;
|
||||
size_t i = 0;
|
||||
while ((c = *src++) != 0) {
|
||||
*dest++ = c;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decode URL-encoded string in place.
|
||||
*/
|
||||
void urldecode_ip(char *str)
|
||||
{
|
||||
unsigned int x;
|
||||
|
||||
for (size_t i = 0; str[i] != 0; i++) {
|
||||
char c = str[i];
|
||||
if (c == '+') {
|
||||
str[i] = ' ';
|
||||
} else if (c == '%') {
|
||||
// decode the byte
|
||||
sscanf(&str[i + 1], "%02x", &x);
|
||||
str[i] = (char)x;
|
||||
|
||||
// shift following chars
|
||||
for (size_t a = i + 3, b = i + 1;; a++, b++) {
|
||||
str[b] = str[a]; // move
|
||||
if (str[a] == 0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* url-decode string, put output in a buffer.
|
||||
*/
|
||||
void urldecode(char *dest, const char *src)
|
||||
{
|
||||
unsigned int x;
|
||||
size_t si = 0, di = 0;
|
||||
|
||||
for (; src[si] != 0; si++) {
|
||||
char c = src[si];
|
||||
if (c == '+') {
|
||||
dest[di++] = ' ';
|
||||
} else if (c == '%') {
|
||||
// decode the byte
|
||||
sscanf(&src[si + 1], "%02x", &x);
|
||||
dest[di++] = (char)x;
|
||||
|
||||
si += 2;
|
||||
} else {
|
||||
dest[di++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
// add terminator
|
||||
dest[di] = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* url-decode string, put output in a buffer.
|
||||
* Limit operation to N chars in input string
|
||||
*/
|
||||
void urldecode_n(char *dest, const char *src, size_t count)
|
||||
{
|
||||
unsigned int x;
|
||||
size_t si = 0, di = 0;
|
||||
|
||||
for (; src[si] != 0 && si < count; si++) {
|
||||
char c = src[si];
|
||||
if (c == '+') {
|
||||
dest[di++] = ' ';
|
||||
} else if (c == '%') {
|
||||
// decode the byte
|
||||
sscanf(&src[si + 1], "%02x", &x);
|
||||
dest[di++] = (char)x;
|
||||
|
||||
si += 2;
|
||||
} else {
|
||||
dest[di++] = c;
|
||||
}
|
||||
}
|
||||
|
||||
// add terminator
|
||||
dest[di] = 0;
|
||||
}
|
||||
|
||||
|
||||
bool get_query_value(char *buffer, const char *querystring, const char *key, size_t buf_len)
|
||||
{
|
||||
bool retval;
|
||||
|
||||
size_t qs_len = strlen(querystring);
|
||||
|
||||
char *ptrn = malloc_s(strlen(key) + 3); // &key=\0
|
||||
sprintf(ptrn, "&%s=", key);
|
||||
matcher_t m = {ptrn, 1}; // pretend ampersand was already matched
|
||||
|
||||
for (size_t i = 0; i < qs_len; i++) {
|
||||
char c = querystring[i];
|
||||
if (matcher_test(&m, (uint8_t)c)) {
|
||||
// found the match
|
||||
i++; // advance past the equals sign
|
||||
|
||||
size_t seg_end = i;
|
||||
while (seg_end < qs_len && querystring[seg_end] != '&') {
|
||||
seg_end++;
|
||||
}
|
||||
|
||||
if (seg_end - i > buf_len) seg_end = i + buf_len;
|
||||
|
||||
if (seg_end == i) {
|
||||
buffer[0] = 0; // strncpy behaves strange with length 0
|
||||
} else {
|
||||
urldecode_n(buffer, querystring + i, seg_end - i);
|
||||
}
|
||||
|
||||
retval = true;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
// not found
|
||||
retval = false;
|
||||
done:
|
||||
free(ptrn);
|
||||
return retval;
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
#define streq(a, b) (strcmp((a), (b)) == 0)
|
||||
#define streqi(a, b) (strcasecmp((a), (b)) == 0)
|
||||
|
||||
/**
|
||||
* Escape string, storing result in a buffer.
|
||||
*/
|
||||
void str_escape(char *dest, const char *src, size_t dest_len);
|
||||
|
||||
|
||||
/**
|
||||
* Escape special chars in a string, IN PLACE.
|
||||
*
|
||||
* If string is too long after escaping, last chars are dropped.
|
||||
*
|
||||
* @param buf the buffer, containing 0-terminated string.
|
||||
* @param buflen buffer length
|
||||
*/
|
||||
void str_escape_ip(char *buf, size_t buf_len);
|
||||
|
||||
|
||||
/**
|
||||
* Get position of needle in a haystack.
|
||||
* -1 if not found.
|
||||
*/
|
||||
int32_t strpos(const char *haystack, const char *needle);
|
||||
|
||||
|
||||
/**
|
||||
* Find substring position, ending at index 'limit'.
|
||||
* Limit <= 0 means no limit.
|
||||
* Returns index of the first character of needle in haystack.
|
||||
*/
|
||||
int32_t strpos_upto(const char *haystack, const char *needle, size_t limit);
|
||||
|
||||
|
||||
/**
|
||||
* Find substring position, ending when endmatch is encountered. (Substring within endmatch *can* be reported).
|
||||
* Returns index of the first character of needle in haystack.
|
||||
*/
|
||||
int32_t strpos_upto_match(const char *haystack, const char *needle, const char *endmatch);
|
||||
|
||||
|
||||
/**
|
||||
* Like sprintf, except without formatting
|
||||
*/
|
||||
size_t str_copy(char * dest, const char *src);
|
||||
|
||||
|
||||
/**
|
||||
* Decode url-encoded string, store result in dest.
|
||||
*/
|
||||
void urldecode(char *dest, const char *src);
|
||||
|
||||
|
||||
/**
|
||||
* Decode url-encoded string in place.
|
||||
*/
|
||||
void urldecode_ip(char *str);
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve & url-decode a query string value by name.
|
||||
*
|
||||
* @param buffer - target buffer
|
||||
* @param querystring - string (foo=bar&baz=moi)
|
||||
* @param key - key to retrieve
|
||||
* @param buf_len - length of the target buffer
|
||||
* @return true if found.
|
||||
*/
|
||||
bool get_query_value(char *buffer, const char *querystring, const char *key, size_t buf_len);
|
||||
@@ -0,0 +1,331 @@
|
||||
#include "timebase.h"
|
||||
#include "bus/event_queue.h"
|
||||
#include "com/debug.h"
|
||||
#include "malloc_safe.h"
|
||||
|
||||
// Time base
|
||||
static volatile ms_time_t SystemTime_ms = 0;
|
||||
|
||||
|
||||
typedef struct {
|
||||
/** User callback with arg */
|
||||
void (*callback)(void *);
|
||||
/** Arg for the arg callback */
|
||||
void *cb_arg;
|
||||
/** Callback interval */
|
||||
ms_time_t interval_ms;
|
||||
/** Counter, when reaches interval_ms, is cleared and callback is called. */
|
||||
ms_time_t countup;
|
||||
/** Unique task ID (for cancelling / modification) */
|
||||
task_pid_t pid;
|
||||
/** Enable flag - disabled tasks still count, but CB is not run */
|
||||
bool enabled;
|
||||
/** Marks that the task is due to be run */
|
||||
bool enqueue;
|
||||
} periodic_task_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
/** User callback with arg */
|
||||
void (*callback)(void *);
|
||||
/** Arg for the arg callback */
|
||||
void *cb_arg;
|
||||
/** Counter, when reaches 0ms, callback is called and the task is removed */
|
||||
ms_time_t countdown_ms;
|
||||
/** Unique task ID (for cancelling / modification) */
|
||||
task_pid_t pid;
|
||||
/** Whether this task is long and needs posting on the queue */
|
||||
bool enqueue;
|
||||
} future_task_t;
|
||||
|
||||
|
||||
static size_t periodic_slot_count = 0;
|
||||
static size_t future_slot_count = 0;
|
||||
|
||||
static periodic_task_t *periodic_tasks;
|
||||
static future_task_t *future_tasks;
|
||||
|
||||
|
||||
/** Init timebase */
|
||||
void timebase_init(size_t periodic, size_t future)
|
||||
{
|
||||
periodic_slot_count = periodic;
|
||||
future_slot_count = future;
|
||||
|
||||
periodic_tasks = calloc_s(periodic, sizeof(periodic_task_t));
|
||||
future_tasks = calloc_s(future, sizeof(future_task_t));
|
||||
}
|
||||
|
||||
|
||||
static task_pid_t next_task_pid = 1; // 0 (PID_NONE) is reserved
|
||||
|
||||
|
||||
/** Get a valid free PID for a new task. */
|
||||
static task_pid_t make_pid(void)
|
||||
{
|
||||
task_pid_t pid = next_task_pid++;
|
||||
|
||||
// make sure no task is given PID 0
|
||||
if (next_task_pid == PID_NONE) {
|
||||
next_task_pid++;
|
||||
}
|
||||
|
||||
return pid;
|
||||
}
|
||||
|
||||
|
||||
/** Take an empty periodic task slot and populate the basics. */
|
||||
static periodic_task_t* claim_periodic_task_slot(ms_time_t interval, bool enqueue)
|
||||
{
|
||||
for (size_t i = 0; i < periodic_slot_count; i++) {
|
||||
periodic_task_t *task = &periodic_tasks[i];
|
||||
if (task->pid != PID_NONE) continue; // task is used
|
||||
|
||||
task->countup = 0;
|
||||
task->interval_ms = interval - 1;
|
||||
task->enqueue = enqueue;
|
||||
task->pid = make_pid();
|
||||
task->enabled = true;
|
||||
return task;
|
||||
}
|
||||
|
||||
error("Periodic task table full.");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/** Take an empty future task slot and populate the basics. */
|
||||
static future_task_t* claim_future_task_slot(ms_time_t delay, bool enqueue)
|
||||
{
|
||||
for (size_t i = 0; i < future_slot_count; i++) {
|
||||
future_task_t *task = &future_tasks[i];
|
||||
if (task->pid != PID_NONE) continue; // task is used
|
||||
|
||||
task->countdown_ms = delay;
|
||||
task->enqueue = enqueue;
|
||||
task->pid = make_pid();
|
||||
return task;
|
||||
}
|
||||
|
||||
error("Future task table full.");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Add a periodic task with an arg. */
|
||||
task_pid_t add_periodic_task(void (*callback)(void*), void* arg, ms_time_t interval, bool enqueue)
|
||||
{
|
||||
periodic_task_t *task = claim_periodic_task_slot(interval, enqueue);
|
||||
|
||||
if (task == NULL) return PID_NONE;
|
||||
|
||||
task->callback = callback;
|
||||
task->cb_arg = arg;
|
||||
|
||||
return task->pid;
|
||||
}
|
||||
|
||||
|
||||
/** Schedule a future task, with uint32_t argument. */
|
||||
task_pid_t schedule_task(void (*callback)(void*), void *arg, ms_time_t delay, bool enqueue)
|
||||
{
|
||||
future_task_t *task = claim_future_task_slot(delay, enqueue);
|
||||
|
||||
if (task == NULL) return PID_NONE;
|
||||
|
||||
task->callback = callback;
|
||||
task->cb_arg = arg;
|
||||
|
||||
return task->pid;
|
||||
}
|
||||
|
||||
|
||||
/** Enable or disable a periodic task. */
|
||||
bool enable_periodic_task(task_pid_t pid, FunctionalState enable)
|
||||
{
|
||||
if (pid == PID_NONE) return false;
|
||||
|
||||
for (size_t i = 0; i < periodic_slot_count; i++) {
|
||||
periodic_task_t *task = &periodic_tasks[i];
|
||||
if (task->pid != pid) continue;
|
||||
|
||||
task->enabled = (enable == ENABLE);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** Check if a periodic task is enabled */
|
||||
bool is_periodic_task_enabled(task_pid_t pid)
|
||||
{
|
||||
if (pid == PID_NONE) return false;
|
||||
|
||||
for (size_t i = 0; i < periodic_slot_count; i++) {
|
||||
periodic_task_t *task = &periodic_tasks[i];
|
||||
if (task->pid != pid) continue;
|
||||
|
||||
return task->enabled;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool reset_periodic_task(task_pid_t pid)
|
||||
{
|
||||
if (pid == PID_NONE) return false;
|
||||
|
||||
for (size_t i = 0; i < periodic_slot_count; i++) {
|
||||
periodic_task_t *task = &periodic_tasks[i];
|
||||
if (task->pid != pid) continue;
|
||||
|
||||
task->countup = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** Remove a periodic task. */
|
||||
bool remove_periodic_task(task_pid_t pid)
|
||||
{
|
||||
if (pid == PID_NONE) return false;
|
||||
|
||||
for (size_t i = 0; i < periodic_slot_count; i++) {
|
||||
periodic_task_t *task = &periodic_tasks[i];
|
||||
if (task->pid != pid) continue;
|
||||
|
||||
task->pid = PID_NONE; // mark unused
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** Abort a scheduled task. */
|
||||
bool abort_scheduled_task(task_pid_t pid)
|
||||
{
|
||||
if (pid == PID_NONE) return false;
|
||||
|
||||
for (size_t i = 0; i < future_slot_count; i++) {
|
||||
future_task_t *task = &future_tasks[i];
|
||||
if (task->pid != pid) continue;
|
||||
|
||||
task->pid = PID_NONE; // mark unused
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/** Run a periodic task */
|
||||
static void run_periodic_task(periodic_task_t *task)
|
||||
{
|
||||
if (!task->enabled) return;
|
||||
|
||||
if (task->enqueue) {
|
||||
// queued task
|
||||
tq_post(task->callback, task->cb_arg);
|
||||
} else {
|
||||
// immediate task
|
||||
task->callback(task->cb_arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Run a future task */
|
||||
static void run_future_task(future_task_t *task)
|
||||
{
|
||||
if (task->enqueue) {
|
||||
// queued task
|
||||
tq_post(task->callback, task->cb_arg);
|
||||
} else {
|
||||
// immediate task
|
||||
task->callback(task->cb_arg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Millisecond callback, should be run in the SysTick handler.
|
||||
*/
|
||||
void timebase_ms_cb(void)
|
||||
{
|
||||
// increment global time
|
||||
SystemTime_ms++;
|
||||
|
||||
// run periodic tasks
|
||||
for (size_t i = 0; i < periodic_slot_count; i++) {
|
||||
periodic_task_t *task = &periodic_tasks[i];
|
||||
if (task->pid == PID_NONE) continue; // unused
|
||||
|
||||
if (task->countup++ >= task->interval_ms) {
|
||||
// run if enabled
|
||||
run_periodic_task(task);
|
||||
// restart counter
|
||||
task->countup = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// run planned future tasks
|
||||
for (size_t i = 0; i < future_slot_count; i++) {
|
||||
future_task_t *task = &future_tasks[i];
|
||||
if (task->pid == PID_NONE) continue; // unused
|
||||
|
||||
if (task->countdown_ms-- == 0) {
|
||||
// run
|
||||
run_future_task(task);
|
||||
// release the slot
|
||||
task->pid = PID_NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** Seconds delay */
|
||||
void delay_s(uint32_t s)
|
||||
{
|
||||
while (s-- != 0) {
|
||||
delay_ms(1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Delay N ms */
|
||||
void delay_ms(ms_time_t ms)
|
||||
{
|
||||
ms_time_t start = SystemTime_ms;
|
||||
while ((SystemTime_ms - start) < ms); // overrun solved by unsigned arithmetic
|
||||
}
|
||||
|
||||
|
||||
/** Get milliseconds elapsed since start timestamp */
|
||||
ms_time_t ms_elapsed(ms_time_t start)
|
||||
{
|
||||
return SystemTime_ms - start;
|
||||
}
|
||||
|
||||
|
||||
/** Get current timestamp. */
|
||||
ms_time_t ms_now(void)
|
||||
{
|
||||
return SystemTime_ms;
|
||||
}
|
||||
|
||||
|
||||
/** Helper for looping with periodic branches */
|
||||
bool ms_loop_elapsed(ms_time_t *start, ms_time_t duration)
|
||||
{
|
||||
if (SystemTime_ms - *start >= duration) {
|
||||
*start = SystemTime_ms;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,159 @@
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* To use the Timebase functionality,
|
||||
* set up SysTick to 1 kHz and call
|
||||
* timebase_ms_cb() in the IRQ.
|
||||
*
|
||||
* If you plan to use pendable future tasks,
|
||||
* also make sure you call run_pending_tasks()
|
||||
* in your main loop.
|
||||
*
|
||||
* This is not needed for non-pendable tasks.
|
||||
*/
|
||||
|
||||
#include "main.h"
|
||||
|
||||
|
||||
/** Task PID. */
|
||||
typedef uint32_t task_pid_t;
|
||||
|
||||
/** Time value in ms */
|
||||
typedef uint32_t ms_time_t;
|
||||
|
||||
// PID value that can be used to indicate no task
|
||||
#define PID_NONE 0
|
||||
|
||||
/** Loop until timeout - use in place of while() or for(). break and continue work too! */
|
||||
#define until_timeout(to_ms) for(uint32_t _utmeo = ms_now(); ms_elapsed(_utmeo) < (to_ms);)
|
||||
|
||||
/** Retry a call until a timeout. Variable 'suc' is set to the return value. Must be defined. */
|
||||
#define retry_TO(to_ms, call) \
|
||||
until_timeout(to_ms) { \
|
||||
suc = call; \
|
||||
if (suc) break; \
|
||||
}
|
||||
|
||||
/** Init timebase, allocate slots for tasks. */
|
||||
void timebase_init(size_t periodic_count, size_t future_count);
|
||||
|
||||
/** Must be called every 1 ms */
|
||||
void timebase_ms_cb(void);
|
||||
|
||||
|
||||
// --- Periodic -----------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add a periodic task with an arg.
|
||||
* @param callback : task callback
|
||||
* @param arg : callback argument
|
||||
* @param interval : task interval (ms)
|
||||
* @param enqueue : put on the task queue when due
|
||||
* @return task PID
|
||||
*/
|
||||
task_pid_t add_periodic_task(void (*callback)(void *), void *arg, ms_time_t interval, bool enqueue);
|
||||
|
||||
|
||||
/** Destroy a periodic task. */
|
||||
bool remove_periodic_task(task_pid_t pid);
|
||||
|
||||
/** Enable or disable a periodic task. Returns true on success. */
|
||||
bool enable_periodic_task(task_pid_t pid, FunctionalState cmd);
|
||||
|
||||
/** Check if a periodic task exists and is enabled. */
|
||||
bool is_periodic_task_enabled(task_pid_t pid);
|
||||
|
||||
/** Reset timer for a task */
|
||||
bool reset_periodic_task(task_pid_t pid);
|
||||
|
||||
|
||||
// --- Future -------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* @brief Schedule a future task, with uint32_t argument.
|
||||
* @param callback : task callback
|
||||
* @param arg : callback argument
|
||||
* @param delay : task delay (ms)
|
||||
* @param enqueue : put on the task queue when due
|
||||
* @return task PID
|
||||
*/
|
||||
task_pid_t schedule_task(void (*callback_arg)(void *), void *arg, ms_time_t delay, bool enqueue);
|
||||
|
||||
|
||||
/** Abort a scheduled task. */
|
||||
bool abort_scheduled_task(task_pid_t pid);
|
||||
|
||||
|
||||
// --- Waiting functions --------------------------------------
|
||||
|
||||
/** Get milliseconds elapsed since start timestamp */
|
||||
ms_time_t ms_elapsed(ms_time_t start);
|
||||
|
||||
|
||||
/** Get current timestamp. */
|
||||
ms_time_t ms_now(void);
|
||||
|
||||
|
||||
/** Delay using SysTick */
|
||||
void delay_ms(ms_time_t ms);
|
||||
|
||||
|
||||
/** Delay N seconds */
|
||||
void delay_s(uint32_t s);
|
||||
|
||||
|
||||
inline __attribute__((always_inline))
|
||||
void delay_cycles(uint32_t n)
|
||||
{
|
||||
uint32_t l = n >> 2;
|
||||
|
||||
__asm volatile(
|
||||
"0: mov r0,r0;"
|
||||
"subs %[count], #1;"
|
||||
"bne 0b;"
|
||||
: [count] "+r"(l)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
inline __attribute__((always_inline))
|
||||
void delay_ns(uint32_t ns)
|
||||
{
|
||||
delay_cycles(ns / 24);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Microsecond delay.
|
||||
* @param us
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void delay_us(uint32_t us)
|
||||
{
|
||||
delay_ns(us * 1150);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check if time since `start` elapsed.
|
||||
*
|
||||
* If so, sets the *start variable to the current time.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ms_time_t s = ms_now();
|
||||
*
|
||||
* while(1) {
|
||||
* if (ms_loop_elapsed(&s, 100)) {
|
||||
* // this is called every 100 ms
|
||||
* }
|
||||
* // ... rest of the loop ...
|
||||
* }
|
||||
*
|
||||
* @param start start time variable
|
||||
* @param duration delay length
|
||||
* @return delay elapsed; start was updated.
|
||||
*/
|
||||
bool ms_loop_elapsed(ms_time_t *start, ms_time_t duration);
|
||||
Reference in New Issue
Block a user