Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/thirdpin/pastilda.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorthirdpin <n_lazareva@mail.ru>2016-07-13 13:55:27 +0300
committerthirdpin <n_lazareva@mail.ru>2016-07-13 13:55:27 +0300
commit03fb98cead3b9b3bf07a786581a7e91817dfcd0e (patch)
treea048a3c7315ea700fd718d130d0f4d7333af8093
parentb5708bc84aa18c19ed384f3ca52e429a7e66cc23 (diff)
initial commit
-rw-r--r--.gitmodules3
-rw-r--r--emb/pastilda/.cproject227
-rw-r--r--emb/pastilda/.project27
-rw-r--r--emb/pastilda/.settings/language.settings.xml25
-rw-r--r--emb/pastilda/app/app.cpp50
-rw-r--r--emb/pastilda/app/app.h30
-rw-r--r--emb/pastilda/app/flash_memory.cpp141
-rw-r--r--emb/pastilda/app/flash_memory.h31
-rw-r--r--emb/pastilda/app/leds.cpp40
-rw-r--r--emb/pastilda/app/leds.h34
-rw-r--r--emb/pastilda/app/usb_dispatcher.cpp52
-rw-r--r--emb/pastilda/app/usb_dispatcher.h33
-rw-r--r--emb/pastilda/hw/clock.h67
-rw-r--r--emb/pastilda/hw/keyboard.h237
-rw-r--r--emb/pastilda/hw/usb_device/ramdisk.c160
-rw-r--r--emb/pastilda/hw/usb_device/ramdisk.h14
-rw-r--r--emb/pastilda/hw/usb_device/usbd_composite.cpp136
-rw-r--r--emb/pastilda/hw/usb_device/usbd_composite.h60
-rw-r--r--emb/pastilda/hw/usb_device/usbd_composite_desc.cpp11
-rw-r--r--emb/pastilda/hw/usb_device/usbd_composite_desc.h162
-rw-r--r--emb/pastilda/hw/usb_host/usbh_host.cpp82
-rw-r--r--emb/pastilda/hw/usb_host/usbh_host.h51
-rw-r--r--emb/pastilda/lib/libusbhost/usbh_config.h62
-rw-r--r--emb/pastilda/lib/libusbhost/usbh_device_driver.h131
-rw-r--r--emb/pastilda/lib/libusbhost/usbh_driver_hid_kbd.c257
-rw-r--r--emb/pastilda/lib/libusbhost/usbh_driver_hid_kbd.h22
-rw-r--r--emb/pastilda/lib/libusbhost/usbh_hubbed.c611
-rw-r--r--emb/pastilda/lib/libusbhost/usbh_hubbed.h79
-rw-r--r--emb/pastilda/lib/libusbhost/usbh_lld_stm32f4.c1059
-rw-r--r--emb/pastilda/lib/libusbhost/usbh_lld_stm32f4.h43
-rw-r--r--emb/pastilda/main.cpp22
-rw-r--r--emb/pastilda/stm32f407vg.ld7
m---------lib/libopencm30
33 files changed, 3966 insertions, 0 deletions
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..bc82d07
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "lib/libopencm3"]
+ path = lib/libopencm3
+ url = https://github.com/thirdpin/libopencm3.git
diff --git a/emb/pastilda/.cproject b/emb/pastilda/.cproject
new file mode 100644
index 0000000..3087e7c
--- /dev/null
+++ b/emb/pastilda/.cproject
@@ -0,0 +1,227 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
+ <storageModule moduleId="org.eclipse.cdt.core.settings">
+ <cconfiguration id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.942108060">
+ <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.942108060" moduleId="org.eclipse.cdt.core.settings" name="Debug">
+ <externalSettings/>
+ <extensions>
+ <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+ <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ </extensions>
+ </storageModule>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="${cross_rm} -rf" description="" id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.942108060" name="Debug" parent="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug">
+ <folderInfo id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.942108060." name="/" resourcePath="">
+ <toolChain id="ilg.gnuarmeclipse.managedbuild.cross.toolchain.elf.debug.845557929" name="Cross ARM GCC" superClass="ilg.gnuarmeclipse.managedbuild.cross.toolchain.elf.debug">
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.level.1046653532" name="Optimization Level" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.level" value="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.level.none" valueType="enumerated"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.messagelength.454964027" name="Message length (-fmessage-length=0)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.messagelength" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.signedchar.1516632541" name="'char' is signed (-fsigned-char)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.signedchar" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.functionsections.999141491" name="Function sections (-ffunction-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.functionsections" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.datasections.942112812" name="Data sections (-fdata-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.datasections" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.level.323334547" name="Debug level" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.level" value="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.level.max" valueType="enumerated"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.format.922969354" name="Debug format" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.format"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.name.1455990715" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.name" value="GNU Tools for ARM Embedded Processors" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.architecture.1201689538" name="Architecture" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.architecture" value="ilg.gnuarmeclipse.managedbuild.cross.option.architecture.arm" valueType="enumerated"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family.1948370853" name="ARM family" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.mcpu.cortex-m4" valueType="enumerated"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset.154989121" name="Instruction set" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset.thumb" valueType="enumerated"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.prefix.1181926008" name="Prefix" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.prefix" value="arm-none-eabi-" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.c.1108842863" name="C compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.c" value="gcc" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.cpp.1140704997" name="C++ compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.cpp" value="g++" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.ar.451825627" name="Archiver" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.ar" value="ar" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.objcopy.1670629754" name="Hex/Bin converter" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.objcopy" value="objcopy" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.objdump.916656774" name="Listing generator" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.objdump" value="objdump" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.size.1212452440" name="Size command" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.size" value="size" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.make.1912596303" name="Build command" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.make" value="make" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.rm.607438027" name="Remove command" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.rm" value="rm" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.createflash.111488546" name="Create flash image" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.createflash" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.printsize.1889312085" name="Print size" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.printsize" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.architecture.1196996559" name="Architecture" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.architecture" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.arch.armv7e-m" valueType="enumerated"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi.985488219" name="Float ABI" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.abi.hard" valueType="enumerated"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit.846503271" name="FPU Type" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.fpu.unit.fpv4spd16" valueType="enumerated"/>
+ <targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform.1706311747" isAbstract="false" osList="all" superClass="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform"/>
+ <builder buildPath="${workspace_loc:/pastilda}/Debug" id="ilg.gnuarmeclipse.managedbuild.cross.builder.502707904" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="ilg.gnuarmeclipse.managedbuild.cross.builder"/>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler.1714403229" name="Cross ARM GNU Assembler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler">
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.usepreprocessor.1478949827" name="Use preprocessor" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.usepreprocessor" value="true" valueType="boolean"/>
+ <inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler.input.535598140" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler.input"/>
+ </tool>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.657593211" name="Cross ARM C Compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler">
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.defs.789067878" name="Defined symbols (-D)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.defs" useByScannerDiscovery="false" valueType="definedSymbols">
+ <listOptionValue builtIn="false" value="STM32F4"/>
+ </option>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.include.paths.1095580488" name="Include paths (-I)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.compiler.include.paths" useByScannerDiscovery="false" valueType="includePath">
+ <listOptionValue builtIn="false" value="&quot;../..\..\lib\libopencm3\include&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;../..\..\lib\libopencm3\lib&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/app}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw/usb_device}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw/usb_host}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libusbhost}&quot;"/>
+ </option>
+ <inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input.338584563" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input"/>
+ </tool>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.268228352" name="Cross ARM C++ Compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler">
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.defs.2136368030" name="Defined symbols (-D)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.defs" useByScannerDiscovery="false" valueType="definedSymbols">
+ <listOptionValue builtIn="false" value="STM32F4"/>
+ </option>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.include.paths.1410012800" name="Include paths (-I)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.compiler.include.paths" useByScannerDiscovery="false" valueType="includePath">
+ <listOptionValue builtIn="false" value="&quot;../..\..\lib\libopencm3\include&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;../..\..\lib\libopencm3\lib&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/app}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw/usb_device}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/hw/usb_host}&quot;"/>
+ <listOptionValue builtIn="false" value="&quot;${workspace_loc:/${ProjName}/lib/libusbhost}&quot;"/>
+ </option>
+ <inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input.583307617" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input"/>
+ </tool>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker.1932922195" name="Cross ARM C Linker" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker">
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.gcsections.236107020" name="Remove unused sections (-Xlinker --gc-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.gcsections" value="true" valueType="boolean"/>
+ </tool>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.775878399" name="Cross ARM C++ Linker" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker">
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.gcsections.631623800" name="Remove unused sections (-Xlinker --gc-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.gcsections" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.scriptfile.1994171085" name="Script files (-T)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.scriptfile" valueType="stringList">
+ <listOptionValue builtIn="false" value="../stm32f407vg.ld"/>
+ </option>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nostart.933236374" name="Do not use standard start files (-nostartfiles)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.nostart" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.libs.730199662" name="Libraries (-l)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.libs" valueType="libs">
+ <listOptionValue builtIn="false" value="opencm3_stm32f4"/>
+ </option>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.paths.136606438" name="Library search path (-L)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.paths" valueType="libPaths">
+ <listOptionValue builtIn="false" value="&quot;../..\..\lib\libopencm3\lib&quot;"/>
+ </option>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usenewlibnano.1859336380" name="Use newlib-nano (--specs=nano.specs)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.usenewlibnano" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.other.67282336" name="Other linker flags" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.other" value="--specs=nosys.specs" valueType="string"/>
+ <inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.input.522811426" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.input">
+ <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+ <additionalInput kind="additionalinput" paths="$(LIBS)"/>
+ </inputType>
+ </tool>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.archiver.1381542134" name="Cross ARM GNU Archiver" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.archiver"/>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.createflash.1226429877" name="Cross ARM GNU Create Flash Image" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.createflash"/>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.createlisting.1930983983" name="Cross ARM GNU Create Listing" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.createlisting">
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.source.2098369275" name="Display source (--source|-S)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.source" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.allheaders.778320952" name="Display all headers (--all-headers|-x)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.allheaders" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.demangle.1429611876" name="Demangle names (--demangle|-C)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.demangle" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.linenumbers.277013702" name="Display line numbers (--line-numbers|-l)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.linenumbers" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.wide.1369528254" name="Wide lines (--wide|-w)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.wide" value="true" valueType="boolean"/>
+ </tool>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.printsize.1407946283" name="Cross ARM GNU Print Size" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.printsize">
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.printsize.format.958464212" name="Size format" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.printsize.format"/>
+ </tool>
+ </toolChain>
+ </folderInfo>
+ </configuration>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+ </cconfiguration>
+ <cconfiguration id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.670767099">
+ <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.670767099" moduleId="org.eclipse.cdt.core.settings" name="Release">
+ <externalSettings/>
+ <extensions>
+ <extension id="org.eclipse.cdt.core.ELF" point="org.eclipse.cdt.core.BinaryParser"/>
+ <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
+ <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
+ </extensions>
+ </storageModule>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="${cross_rm} -rf" description="" id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.670767099" name="Release" parent="ilg.gnuarmeclipse.managedbuild.cross.config.elf.release">
+ <folderInfo id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.670767099." name="/" resourcePath="">
+ <toolChain id="ilg.gnuarmeclipse.managedbuild.cross.toolchain.elf.release.1989269394" name="Cross ARM GCC" superClass="ilg.gnuarmeclipse.managedbuild.cross.toolchain.elf.release">
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.level.1181304486" name="Optimization Level" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.level" value="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.level.size" valueType="enumerated"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.messagelength.1300842544" name="Message length (-fmessage-length=0)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.messagelength" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.signedchar.1498692711" name="'char' is signed (-fsigned-char)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.signedchar" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.functionsections.1191947121" name="Function sections (-ffunction-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.functionsections" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.datasections.760184152" name="Data sections (-fdata-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.optimization.datasections" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.level.152024104" name="Debug level" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.level"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.format.2100377271" name="Debug format" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.debugging.format"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.name.77845878" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.toolchain.name" value="GNU Tools for ARM Embedded Processors" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.architecture.971661837" name="Architecture" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.architecture" value="ilg.gnuarmeclipse.managedbuild.cross.option.architecture.arm" valueType="enumerated"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family.654784178" name="ARM family" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.family" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.mcpu.cortex-m3" valueType="enumerated"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset.118600130" name="Instruction set" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset" value="ilg.gnuarmeclipse.managedbuild.cross.option.arm.target.instructionset.thumb" valueType="enumerated"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.prefix.491859519" name="Prefix" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.prefix" value="arm-none-eabi-" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.c.497410578" name="C compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.c" value="gcc" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.cpp.865840489" name="C++ compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.cpp" value="g++" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.ar.2112933359" name="Archiver" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.ar" value="ar" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.objcopy.1006900743" name="Hex/Bin converter" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.objcopy" value="objcopy" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.objdump.90311104" name="Listing generator" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.objdump" value="objdump" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.size.1368671276" name="Size command" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.size" value="size" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.make.1359291204" name="Build command" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.make" value="make" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.command.rm.1924596383" name="Remove command" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.command.rm" value="rm" valueType="string"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.createflash.25173340" name="Create flash image" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.createflash" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.printsize.1235822610" name="Print size" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.addtools.printsize" value="true" valueType="boolean"/>
+ <targetPlatform archList="all" binaryParser="org.eclipse.cdt.core.ELF" id="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform.655385105" isAbstract="false" osList="all" superClass="ilg.gnuarmeclipse.managedbuild.cross.targetPlatform"/>
+ <builder buildPath="${workspace_loc:/pastilda}/Release" id="ilg.gnuarmeclipse.managedbuild.cross.builder.534276542" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="Gnu Make Builder" superClass="ilg.gnuarmeclipse.managedbuild.cross.builder"/>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler.2054116733" name="Cross ARM GNU Assembler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler">
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.usepreprocessor.1788270189" name="Use preprocessor" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.assembler.usepreprocessor" value="true" valueType="boolean"/>
+ <inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler.input.2056331545" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.assembler.input"/>
+ </tool>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.2014734394" name="Cross ARM C Compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler">
+ <inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input.1087794296" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input"/>
+ </tool>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.569181729" name="Cross ARM C++ Compiler" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler">
+ <inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input.41846961" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input"/>
+ </tool>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker.1462231901" name="Cross ARM C Linker" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.c.linker">
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.gcsections.820377161" name="Remove unused sections (-Xlinker --gc-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.c.linker.gcsections" value="true" valueType="boolean"/>
+ </tool>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.1955167908" name="Cross ARM C++ Linker" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker">
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.gcsections.855734776" name="Remove unused sections (-Xlinker --gc-sections)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.cpp.linker.gcsections" value="true" valueType="boolean"/>
+ <inputType id="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.input.1413358125" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.linker.input">
+ <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/>
+ <additionalInput kind="additionalinput" paths="$(LIBS)"/>
+ </inputType>
+ </tool>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.archiver.1719701408" name="Cross ARM GNU Archiver" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.archiver"/>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.createflash.988631903" name="Cross ARM GNU Create Flash Image" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.createflash"/>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.createlisting.758550459" name="Cross ARM GNU Create Listing" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.createlisting">
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.source.485680272" name="Display source (--source|-S)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.source" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.allheaders.1800820333" name="Display all headers (--all-headers|-x)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.allheaders" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.demangle.449005908" name="Demangle names (--demangle|-C)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.demangle" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.linenumbers.1274427996" name="Display line numbers (--line-numbers|-l)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.linenumbers" value="true" valueType="boolean"/>
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.wide.2128727023" name="Wide lines (--wide|-w)" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.createlisting.wide" value="true" valueType="boolean"/>
+ </tool>
+ <tool id="ilg.gnuarmeclipse.managedbuild.cross.tool.printsize.782061307" name="Cross ARM GNU Print Size" superClass="ilg.gnuarmeclipse.managedbuild.cross.tool.printsize">
+ <option id="ilg.gnuarmeclipse.managedbuild.cross.option.printsize.format.1062092396" name="Size format" superClass="ilg.gnuarmeclipse.managedbuild.cross.option.printsize.format"/>
+ </tool>
+ </toolChain>
+ </folderInfo>
+ </configuration>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
+ </cconfiguration>
+ </storageModule>
+ <storageModule moduleId="cdtBuildSystem" version="4.0.0">
+ <project id="pastilda.ilg.gnuarmeclipse.managedbuild.cross.target.elf.1889794787" name="Executable" projectType="ilg.gnuarmeclipse.managedbuild.cross.target.elf"/>
+ </storageModule>
+ <storageModule moduleId="scannerConfiguration">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+ <scannerConfigBuildInfo instanceId="ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.670767099;ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.670767099.;ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.2014734394;ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input.1087794296">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.942108060;ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.942108060.;ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.268228352;ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input.583307617">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.942108060;ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.942108060.;ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.657593211;ilg.gnuarmeclipse.managedbuild.cross.tool.c.compiler.input.338584563">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+ </scannerConfigBuildInfo>
+ <scannerConfigBuildInfo instanceId="ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.670767099;ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.670767099.;ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.569181729;ilg.gnuarmeclipse.managedbuild.cross.tool.cpp.compiler.input.41846961">
+ <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
+ </scannerConfigBuildInfo>
+ </storageModule>
+ <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
+ <storageModule moduleId="refreshScope" versionNumber="2">
+ <configuration configurationName="Debug">
+ <resource resourceType="PROJECT" workspacePath="/pastilda"/>
+ </configuration>
+ <configuration configurationName="Release">
+ <resource resourceType="PROJECT" workspacePath="/pastilda"/>
+ </configuration>
+ </storageModule>
+</cproject>
diff --git a/emb/pastilda/.project b/emb/pastilda/.project
new file mode 100644
index 0000000..85fef35
--- /dev/null
+++ b/emb/pastilda/.project
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>pastilda</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
+ <triggers>clean,full,incremental,</triggers>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
+ <triggers>full,incremental,</triggers>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.cdt.core.cnature</nature>
+ <nature>org.eclipse.cdt.core.ccnature</nature>
+ <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
+ <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
+ </natures>
+</projectDescription>
diff --git a/emb/pastilda/.settings/language.settings.xml b/emb/pastilda/.settings/language.settings.xml
new file mode 100644
index 0000000..b82979e
--- /dev/null
+++ b/emb/pastilda/.settings/language.settings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<project>
+ <configuration id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.debug.942108060" name="Debug">
+ <extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
+ <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
+ <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
+ <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
+ <provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector" console="false" env-hash="228017701990115227" id="ilg.gnuarmeclipse.managedbuild.cross.GCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT GCC Built-in Compiler Settings Cross ARM" parameter="${COMMAND} ${FLAGS} ${cross_toolchain_flags} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
+ <language-scope id="org.eclipse.cdt.core.gcc"/>
+ <language-scope id="org.eclipse.cdt.core.g++"/>
+ </provider>
+ </extension>
+ </configuration>
+ <configuration id="ilg.gnuarmeclipse.managedbuild.cross.config.elf.release.670767099" name="Release">
+ <extension point="org.eclipse.cdt.core.LanguageSettingsProvider">
+ <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
+ <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
+ <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/>
+ <provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector" console="false" env-hash="201214536915785275" id="ilg.gnuarmeclipse.managedbuild.cross.GCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT GCC Built-in Compiler Settings Cross ARM" parameter="${COMMAND} ${FLAGS} ${cross_toolchain_flags} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
+ <language-scope id="org.eclipse.cdt.core.gcc"/>
+ <language-scope id="org.eclipse.cdt.core.g++"/>
+ </provider>
+ </extension>
+ </configuration>
+</project>
diff --git a/emb/pastilda/app/app.cpp b/emb/pastilda/app/app.cpp
new file mode 100644
index 0000000..e969f64
--- /dev/null
+++ b/emb/pastilda/app/app.cpp
@@ -0,0 +1,50 @@
+#include "app.h"
+#include "stdio.h"
+using namespace Application;
+
+#ifdef DEBUG
+ #define DEBUG_PRINT(x) printf(x)
+#else
+ #define DEBUG_PRINT(x) do {} while (0)
+#endif
+
+App *app_pointer;
+
+App::App()
+{
+ app_pointer = this;
+ clock_setup();
+ systick_init();
+
+ _leds_api = new LEDS_api();
+/////////////////////////////////////////////////////////////////////////////////////////
+ //spi and cs pin for sst25_driver
+// SPI_Conf spi_conf;
+// spi_conf.spi_number = 1;
+// spi_conf.scl_pin = PA5;
+// spi_conf.miso_pin = PA6;
+// spi_conf.mosi_pin = PA7;
+// _spi_ext = new SPI_ext(spi_conf);
+// _spi_ext->disable();
+// _spi_ext->set_baudrate_prescaler(SPI_CPP_Extension::BaudRate::BAUDRATE_FPCLK_DIV_2);
+// _spi_ext->set_clock_polarity(SPI_CPP_Extension::Polarity::POLARITY_HIGH);
+// _spi_ext->set_clock_phase(Phase::PHASE_HIGH);
+// _spi_ext->set_data_drame_format(DataFrameFormat::DFF_8BIT);
+// _spi_ext->set_bit_position(BitPos::MSB_FIRST);
+// _spi_ext->set_software_slave_management(State::ENABLE);
+// _spi_ext->set_nss(NssState::HIGH);
+// _spi_ext->enable();
+//
+// GPIO_ext cs_pin(PA4);
+// cs_pin.mode_setup(Mode::OUTPUT, PullMode::NO_PULL);
+// cs_pin.set_output_options(OutputType::PUSH_PULL, Speed::FAST_50MHz);
+///////////////////////////////////////////////////////////////////////////////////////////
+ delay_ms(1000);
+
+ usb_dispatcher = new USB_dispatcher();
+}
+void App::process()
+{
+ _leds_api->toggle();
+ usb_dispatcher->process();
+}
diff --git a/emb/pastilda/app/app.h b/emb/pastilda/app/app.h
new file mode 100644
index 0000000..80258e2
--- /dev/null
+++ b/emb/pastilda/app/app.h
@@ -0,0 +1,30 @@
+#ifndef APP_H
+#define APP_H
+
+#include <string.h>
+#include "clock.h"
+#include "gpio_ext.h"
+#include "systick_ext.h"
+#include "leds.h"
+#include "usb_dispatcher.h"
+#include "spi_ext.h"
+
+using namespace LEDS_API;
+using namespace GPIO_CPP_Extension;
+using namespace SPI_CPP_Extension;
+
+namespace Application
+{
+ class App
+ {
+ public:
+ App();
+ void process();
+
+ private:
+ LEDS_api *_leds_api;
+ USB_dispatcher *usb_dispatcher;
+ SPI_ext *_spi_ext;
+ };
+}
+#endif
diff --git a/emb/pastilda/app/flash_memory.cpp b/emb/pastilda/app/flash_memory.cpp
new file mode 100644
index 0000000..23dde5b
--- /dev/null
+++ b/emb/pastilda/app/flash_memory.cpp
@@ -0,0 +1,141 @@
+#include "flash_memory.h"
+#include "systick_ext.h"
+
+#define WBVAL(x) ((x) & 0xFF), (((x) >> 8) & 0xFF)
+#define QBVAL(x) ((x) & 0xFF), (((x) >> 8) & 0xFF), (((x) >> 16) & 0xFF), (((x) >> 24) & 0xFF)
+#define BYTES_PER_SECTOR 512
+#define SECTORS_PER_CLUSTER 4
+#define RESERVED_SECTORS 1
+#define FAT_COPIES 2
+#define ROOT_ENTRIES 512
+
+FlashMemory *flash_pointer;
+
+FlashMemory::FlashMemory(struct block_device *dev)
+{
+ flash_pointer = this;
+
+ SPI_CPP_Extension::SPI_Conf sst25_conf = { 1, PB5, PB4, PB3 };
+ _spi = new SPI_ext(sst25_conf);
+
+ _spi->reset();
+ _spi->disable();
+ _spi->set_master_mode();
+ _spi->set_baudrate_prescaler(BAUDRATE_FPCLK_DIV_2);
+ _spi->set_standard_mode(MODE_0);
+ _spi->set_data_drame_format(DFF_8BIT);
+ _spi->set_bit_position(MSB_FIRST);
+ _spi->enable_ss_output();
+ _spi->set_software_slave_management(State::ENABLE);
+ _spi->set_nss(HIGH);
+ _spi->enable();
+
+ _sst25 = new SST25(_spi, PA15);
+ _sst25->disable_wtite_protection();
+
+ dev->get_sector_size = get_sector_size;
+ dev->read_sectors = read_sectors;
+ dev->write_sectors = write_sectors;
+}
+
+uint16_t FlashMemory::get_sector_size(const struct block_device *dev)
+{
+ (void)dev;
+ return (FAKE_SECTOR_SIZE);
+}
+
+int FlashMemory::read_sectors(const struct block_device *dev, uint32_t sector, uint32_t count, void *buf)
+{
+ (void)dev;
+ uint32_t end_sector = sector + count - 1;
+
+ uint32_t real_start_sector = sector / 8;
+ uint32_t real_end_sector = end_sector / 8;
+ uint32_t real_sector_count = real_end_sector - real_start_sector + 1;
+
+ uint32_t data_size = real_sector_count * SECTOR_SIZE;
+ uint8_t data[data_size];
+
+ uint32_t ok_sectors = flash_pointer->_sst25->read_sectors(real_start_sector, real_sector_count, data);
+
+ if (ok_sectors != real_sector_count) {
+ return (0);
+ }
+
+ uint32_t start_address = (real_start_sector * SECTOR_SIZE) + ((sector % 8) * FAKE_SECTOR_SIZE);
+ uint32_t end_address = start_address + (count * FAKE_SECTOR_SIZE);
+
+ for (int i = start_address, j = 0; i < end_address; i++, j++) {
+ ((uint8_t*)buf)[j] = data[i];
+ }
+
+ return (count);
+}
+
+int FlashMemory::write_sectors(const struct block_device *dev, uint32_t sector, uint32_t count, const void *buf)
+{
+ (void)dev;
+ uint32_t end_sector = sector + count - 1;
+
+ uint32_t real_start_sector = sector / 8;
+ uint32_t real_end_sector = end_sector / 8;
+ uint32_t real_sector_count = real_end_sector - real_start_sector + 1;
+
+
+ uint32_t copy_size = real_sector_count * SECTOR_SIZE;
+ uint8_t sector_copy[copy_size];
+
+ uint32_t ok_sectors = flash_pointer->_sst25->read_sectors(real_start_sector, real_sector_count, sector_copy);
+
+ if (ok_sectors != real_sector_count) {
+ return (0);
+ }
+
+ for (int i = 0; i < real_sector_count; i++) {
+ flash_pointer->_sst25->erase_sector(real_start_sector + i);
+ }
+
+ uint32_t start_address = (real_start_sector * SECTOR_SIZE) + ((sector % 8) * FAKE_SECTOR_SIZE);
+ uint32_t end_address = start_address + (count * FAKE_SECTOR_SIZE);
+
+ for (int i = start_address, j = 0; i <= end_address; i++, j++) {
+ sector_copy[i] = ((uint8_t*)buf)[j];
+ }
+
+ ok_sectors = flash_pointer->_sst25->write_sectors(real_start_sector, real_sector_count, sector_copy);
+ if (ok_sectors != real_sector_count) {
+ return (0);
+ }
+
+
+ return (count);
+}
+
+int FlashMemory::flash_read(uint32_t lba, uint8_t *copy_to)
+{
+ memset(copy_to, 0, FAKE_SECTOR_SIZE);
+ if (lba >= FAKE_SECTOR_COUNT) {
+ return (1);
+ }
+ else {
+ read_sectors(0, lba, 1, copy_to);
+ return (0);
+ }
+}
+int FlashMemory::flash_write(uint32_t lba, const uint8_t *copy_from)
+{
+ ///TODO: check for lba > 3
+ if (lba >= FAKE_SECTOR_COUNT) {
+ return (1);
+ }
+ else {
+ write_sectors(0, lba, 1, copy_from);
+ return (1);
+ }
+ // ignore writes
+ return (0);
+}
+int FlashMemory::flash_blocks(void)
+{
+ return (FAKE_SECTOR_COUNT);
+}
diff --git a/emb/pastilda/app/flash_memory.h b/emb/pastilda/app/flash_memory.h
new file mode 100644
index 0000000..389f0da
--- /dev/null
+++ b/emb/pastilda/app/flash_memory.h
@@ -0,0 +1,31 @@
+#ifndef FLASH_MEMORY_H
+#define FLASH_MEMORY_H
+
+#include <string.h>
+#include "blockdev.h"
+
+#include "spi_ext.h"
+#include "SST25.h"
+
+using namespace SPI_CPP_Extension;
+
+constexpr uint16_t FAKE_SECTOR_SIZE = 512;
+constexpr uint16_t FAKE_SECTOR_COUNT = (MEMORY_SIZE / FAKE_SECTOR_SIZE);
+
+class FlashMemory
+{
+public:
+ FlashMemory(struct block_device *dev);
+ static uint16_t get_sector_size(const struct block_device *dev);
+ static int read_sectors(const struct block_device *dev, uint32_t sector, uint32_t count, void *buf);
+ static int write_sectors(const struct block_device *dev, uint32_t sector, uint32_t count, const void *buf);
+
+ int flash_read(uint32_t lba, uint8_t *copy_to);
+ int flash_write(uint32_t lba, const uint8_t *copy_from);
+ int flash_blocks(void);
+private:
+ SST25 *_sst25;
+ SPI_ext *_spi;
+};
+
+#endif
diff --git a/emb/pastilda/app/leds.cpp b/emb/pastilda/app/leds.cpp
new file mode 100644
index 0000000..5abec58
--- /dev/null
+++ b/emb/pastilda/app/leds.cpp
@@ -0,0 +1,40 @@
+#include "leds.h"
+
+using namespace LEDS_API;
+
+LEDS_api::LEDS_api()
+{
+ _leds[0] = new GPIO_ext(LED_A);
+ _leds[1] = new GPIO_ext(LED_B);
+ _leds[0]->mode_setup(Mode::OUTPUT, PullMode::NO_PULL);
+ _leds[1]->mode_setup(Mode::OUTPUT, PullMode::NO_PULL);
+
+ _leds_state = LEDS_INI_STATE;
+ _timer_leds_toggle = new TimerMs(TimerMode::CYCLE, LEDS_TOGGLE_PERIOD_MS);
+}
+
+void LEDS_api::toggle()
+{
+ if (_timer_leds_toggle->timeout()) {
+ leds_toggle();
+ }
+}
+
+void LEDS_api::leds_toggle()
+{
+ uint8_t mask = LEDS_INI_STATE;
+ for(int i = 0; i < LEDS_COUNT; i++) {
+ if (!(_leds_state & mask)) {
+ _leds[i]->set();
+ }
+ else {
+ _leds[i]->clear();
+ }
+
+ mask = mask << 1;
+ }
+
+ if( ++_leds_state > LEDS_MAX_STATE ) {
+ _leds_state = LEDS_INI_STATE;
+ }
+}
diff --git a/emb/pastilda/app/leds.h b/emb/pastilda/app/leds.h
new file mode 100644
index 0000000..691d0f0
--- /dev/null
+++ b/emb/pastilda/app/leds.h
@@ -0,0 +1,34 @@
+#ifndef LEDS_API_H
+#define LEDS_API_H
+
+#include "gpio_ext.h"
+#include "systick_ext.h"
+
+using namespace GPIO_CPP_Extension;
+
+namespace LEDS_API
+{
+ constexpr Pinout LED_A = PD12;
+ constexpr Pinout LED_B = PD13;
+ constexpr uint8_t LEDS_COUNT = 0x02;
+ constexpr uint8_t LEDS_MAX_STATE = 0x02;
+ constexpr uint8_t LEDS_INI_STATE = 0x01;
+ constexpr uint32_t LEDS_TOGGLE_PERIOD_MS = 500;
+
+ class LEDS_api
+ {
+ public:
+ LEDS_api();
+ void toggle();
+
+ private:
+ TimerMs *_timer_leds_toggle;
+ GPIO_ext *_leds[LEDS_COUNT];
+
+ uint8_t _leds_state;
+
+ void leds_toggle();
+ };
+}
+
+#endif
diff --git a/emb/pastilda/app/usb_dispatcher.cpp b/emb/pastilda/app/usb_dispatcher.cpp
new file mode 100644
index 0000000..edb89e1
--- /dev/null
+++ b/emb/pastilda/app/usb_dispatcher.cpp
@@ -0,0 +1,52 @@
+#include "usb_dispatcher.h"
+
+USB_dispatcher *dispatcher_pointer;
+
+USB_dispatcher::USB_dispatcher()
+{
+ dispatcher_pointer = this;
+ usb_composite = new USB_composite();
+ usb_host = new USB_host(redirect, control_interception);
+ _interception_enabled = false;
+}
+
+void USB_dispatcher::redirect(uint8_t *data, uint8_t len)
+{
+ dispatcher_pointer->usb_composite->usb_send_packet(data, len);
+}
+
+void USB_dispatcher::control_interception()
+{
+ memset(dispatcher_pointer->key, 0, 8);
+ dispatcher_pointer->key[2] = KEY_W;
+ dispatcher_pointer->key[3] = KEY_O;
+ dispatcher_pointer->key[4] = KEY_N;
+ dispatcher_pointer->key[5] = KEY_D;
+ dispatcher_pointer->key[6] = KEY_E;
+ dispatcher_pointer->key[7] = KEY_R;
+ dispatcher_pointer->usb_composite->usb_send_packet(dispatcher_pointer->key, 8);
+
+ dispatcher_pointer->key[2] = 0;
+ dispatcher_pointer->key[3] = 0;
+ dispatcher_pointer->key[4] = 0;
+ dispatcher_pointer->key[5] = 0;
+ dispatcher_pointer->key[6] = 0;
+ dispatcher_pointer->key[7] = 0;
+ dispatcher_pointer->usb_composite->usb_send_packet(dispatcher_pointer->key, 8);
+
+ dispatcher_pointer->key[2] = KEY_SPACEBAR;
+ dispatcher_pointer->key[3] = KEY_W;
+ dispatcher_pointer->key[4] = KEY_O;
+ dispatcher_pointer->key[5] = KEY_M;
+ dispatcher_pointer->key[6] = KEY_A;
+ dispatcher_pointer->key[7] = KEY_N;
+ dispatcher_pointer->usb_composite->usb_send_packet(dispatcher_pointer->key, 8);
+
+ dispatcher_pointer->key[2] = 0;
+ dispatcher_pointer->key[3] = 0;
+ dispatcher_pointer->key[4] = 0;
+ dispatcher_pointer->key[5] = 0;
+ dispatcher_pointer->key[6] = 0;
+ dispatcher_pointer->key[7] = 0;
+ dispatcher_pointer->usb_composite->usb_send_packet(dispatcher_pointer->key, 8);
+}
diff --git a/emb/pastilda/app/usb_dispatcher.h b/emb/pastilda/app/usb_dispatcher.h
new file mode 100644
index 0000000..ae748f5
--- /dev/null
+++ b/emb/pastilda/app/usb_dispatcher.h
@@ -0,0 +1,33 @@
+#ifndef USB_DISPATCHER_H
+#define USB_DISPATCHER_H
+
+#include "usbh_host.h"
+#include "usbd_composite.h"
+extern "C"
+{
+#include "keyboard.h"
+}
+
+class USB_dispatcher
+{
+public:
+ USB_composite *usb_composite;
+ USB_host *usb_host;
+ uint8_t key[8];
+
+ USB_dispatcher();
+
+ static void redirect(uint8_t *data, uint8_t len);
+ static void control_interception();
+ void do_work();
+ void process()
+ {
+ usb_host->poll();
+ }
+private:
+ bool _interception_enabled;
+
+
+};
+
+#endif
diff --git a/emb/pastilda/hw/clock.h b/emb/pastilda/hw/clock.h
new file mode 100644
index 0000000..6ad3e43
--- /dev/null
+++ b/emb/pastilda/hw/clock.h
@@ -0,0 +1,67 @@
+#ifndef CLOCK_H
+#define CLOCK_H
+
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/flash.h>
+
+#ifdef STM32F2
+static constexpr struct rcc_clock_scale rcc_hse_25mhz_to_hclk_120mhz =
+{
+ 20 /*PLLM*/, 192 /*PLLN*/, 2 /*PLLP*/, 5 /*PLLQ*/,
+ (FLASH_ACR_ICE | FLASH_ACR_DCE | FLASH_ACR_LATENCY_3WS) /*FLASH CONFIG*/,
+ RCC_CFGR_HPRE_DIV_NONE /*HPRE*/,
+ RCC_CFGR_PPRE_DIV_4 /*PPRE1*/, RCC_CFGR_PPRE_DIV_2 /*PPRE2*/,
+ 30000000 /*APB1_FREQ*/, 60000000 /*APB2_FREQ*/
+};
+
+static constexpr struct rcc_clock_scale rcc_hse_8mhz_to_hclk_120mhz =
+{
+ 8 /*PLLM*/, 120 /*PLLN*/, 2 /*PLLP*/, 5 /*PLLQ*/,
+ FLASH_ACR_ICE | FLASH_ACR_DCE | FLASH_ACR_LATENCY_3WS /*FLASH CONFIG*/,
+ RCC_CFGR_HPRE_DIV_NONE /*HPRE*/,
+ RCC_CFGR_PPRE_DIV_4 /*PPRE1*/, RCC_CFGR_PPRE_DIV_2 /*PPRE2*/,
+ 30000000 /*APB1_FREQ*/, 60000000 /*APB2_FREQ*/
+};
+#endif
+
+#ifdef STM32F4
+static constexpr struct rcc_clock_scale rcc_hse_25mhz_to_hclk_120mhz =
+{
+ 15 /*PLLM*/, 144 /*PLLN*/, 2 /*PLLP*/, 5 /*PLLQ*/,
+ (FLASH_ACR_ICE | FLASH_ACR_DCE | FLASH_ACR_LATENCY_3WS) /*FLASH CONFIG*/,
+ RCC_CFGR_HPRE_DIV_NONE /*HPRE*/,
+ RCC_CFGR_PPRE_DIV_4 /*PPRE1*/, RCC_CFGR_PPRE_DIV_2 /*PPRE2*/,
+ 1 /*POWER SAVE*/, 120000000 /*AHB FREQ*/,
+ 30000000 /*APB1_FREQ*/, 60000000 /*APB2_FREQ*/
+};
+
+static constexpr struct rcc_clock_scale rcc_hse_8mhz_to_hclk_120mhz =
+{
+ 4 /*PLLM*/, 120 /*PLLN*/, 2 /*PLLP*/, 5 /*PLLQ*/,
+ FLASH_ACR_ICE | FLASH_ACR_DCE | FLASH_ACR_LATENCY_3WS /*FLASH CONFIG*/,
+ RCC_CFGR_HPRE_DIV_NONE /*HPRE*/,
+ RCC_CFGR_PPRE_DIV_4 /*PPRE1*/, RCC_CFGR_PPRE_DIV_2 /*PPRE2*/,
+ 1 /*POWER SAVE*/, 120000000 /*AHB FREQ*/,
+ 30000000 /*APB1_FREQ*/, 60000000 /*APB2_FREQ*/
+};
+#endif
+
+static void clock_setup()
+{
+ rcc_clock_setup_hse_3v3(&rcc_hse_8mhz_to_hclk_120mhz);
+
+ rcc_periph_clock_enable(rcc_periph_clken::RCC_GPIOA);
+ rcc_periph_clock_enable(rcc_periph_clken::RCC_GPIOB);
+ rcc_periph_clock_enable(rcc_periph_clken::RCC_GPIOC);
+ rcc_periph_clock_enable(rcc_periph_clken::RCC_GPIOD);
+ rcc_periph_clock_enable(rcc_periph_clken::RCC_USART6); //usb_host helper
+ rcc_periph_clock_enable(rcc_periph_clken::RCC_TIM6); //usb_host
+ rcc_periph_clock_enable(rcc_periph_clken::RCC_SPI1); //sst25
+ //rcc_periph_clock_enable(rcc_periph_clken::RCC_TIM9);
+ //rcc_periph_clock_enable(rcc_periph_clken::RCC_PWR);
+ //rcc_periph_clock_enable(rcc_periph_clken::RCC_SYSCFG);
+ rcc_periph_clock_enable(rcc_periph_clken::RCC_OTGFS); //device
+ rcc_periph_clock_enable(rcc_periph_clken::RCC_OTGHS); //host
+}
+
+#endif
diff --git a/emb/pastilda/hw/keyboard.h b/emb/pastilda/hw/keyboard.h
new file mode 100644
index 0000000..7a59e41
--- /dev/null
+++ b/emb/pastilda/hw/keyboard.h
@@ -0,0 +1,237 @@
+#ifndef KEYBOARD_H
+#define KEYBOARD_H
+
+#define KEY_NONE 0x00
+#define KEY_ERRORROLLOVER 0x01
+#define KEY_POSTFAIL 0x02
+#define KEY_ERRORUNDEFINED 0x03
+#define KEY_A 0x04
+#define KEY_B 0x05
+#define KEY_C 0x06
+#define KEY_D 0x07
+#define KEY_E 0x08
+#define KEY_F 0x09
+#define KEY_G 0x0A
+#define KEY_H 0x0B
+#define KEY_I 0x0C
+#define KEY_J 0x0D
+#define KEY_K 0x0E
+#define KEY_L 0x0F
+#define KEY_M 0x10
+#define KEY_N 0x11
+#define KEY_O 0x12
+#define KEY_P 0x13
+#define KEY_Q 0x14
+#define KEY_R 0x15
+#define KEY_S 0x16
+#define KEY_T 0x17
+#define KEY_U 0x18
+#define KEY_V 0x19
+#define KEY_W 0x1A
+#define KEY_X 0x1B
+#define KEY_Y 0x1C
+#define KEY_Z 0x1D
+#define KEY_1_EXCLAMATION_MARK 0x1E
+#define KEY_2_AT 0x1F
+#define KEY_3_NUMBER_SIGN 0x20
+#define KEY_4_DOLLAR 0x21
+#define KEY_5_PERCENT 0x22
+#define KEY_6_CARET 0x23
+#define KEY_7_AMPERSAND 0x24
+#define KEY_8_ASTERISK 0x25
+#define KEY_9_OPARENTHESIS 0x26
+#define KEY_0_CPARENTHESIS 0x27
+#define KEY_ENTER 0x28
+#define KEY_ESCAPE 0x29
+#define KEY_BACKSPACE 0x2A
+#define KEY_TAB 0x2B
+#define KEY_SPACEBAR 0x2C
+#define KEY_MINUS_UNDERSCORE 0x2D
+#define KEY_EQUAL_PLUS 0x2E
+#define KEY_OBRACKET_AND_OBRACE 0x2F
+#define KEY_CBRACKET_AND_CBRACE 0x30
+#define KEY_BACKSLASH_VERTICAL_BAR 0x31
+#define KEY_NONUS_NUMBER_SIGN_TILDE 0x32
+#define KEY_SEMICOLON_COLON 0x33
+#define KEY_SINGLE_AND_DOUBLE_QUOTE 0x34
+#define KEY_GRAVE_ACCENT_AND_TILDE 0x35
+#define KEY_COMMA_AND_LESS 0x36
+#define KEY_DOT_GREATER 0x37
+#define KEY_SLASH_QUESTION 0x38
+#define KEY_CAPS_LOCK 0x39
+#define KEY_F1 0x3A
+#define KEY_F2 0x3B
+#define KEY_F3 0x3C
+#define KEY_F4 0x3D
+#define KEY_F5 0x3E
+#define KEY_F6 0x3F
+#define KEY_F7 0x40
+#define KEY_F8 0x41
+#define KEY_F9 0x42
+#define KEY_F10 0x43
+#define KEY_F11 0x44
+#define KEY_F12 0x45
+#define KEY_PRINTSCREEN 0x46
+#define KEY_SCROLL_LOCK 0x47
+#define KEY_PAUSE 0x48
+#define KEY_INSERT 0x49
+#define KEY_HOME 0x4A
+#define KEY_PAGEUP 0x4B
+#define KEY_DELETE 0x4C
+#define KEY_END1 0x4D
+#define KEY_PAGEDOWN 0x4E
+#define KEY_RIGHTARROW 0x4F
+#define KEY_LEFTARROW 0x50
+#define KEY_DOWNARROW 0x51
+#define KEY_UPARROW 0x52
+#define KEY_KEYPAD_NUM_LOCK_AND_CLEAR 0x53
+#define KEY_KEYPAD_SLASH 0x54
+#define KEY_KEYPAD_ASTERIKS 0x55
+#define KEY_KEYPAD_MINUS 0x56
+#define KEY_KEYPAD_PLUS 0x57
+#define KEY_KEYPAD_ENTER 0x58
+#define KEY_KEYPAD_1_END 0x59
+#define KEY_KEYPAD_2_DOWN_ARROW 0x5A
+#define KEY_KEYPAD_3_PAGEDN 0x5B
+#define KEY_KEYPAD_4_LEFT_ARROW 0x5C
+#define KEY_KEYPAD_5 0x5D
+#define KEY_KEYPAD_6_RIGHT_ARROW 0x5E
+#define KEY_KEYPAD_7_HOME 0x5F
+#define KEY_KEYPAD_8_UP_ARROW 0x60
+#define KEY_KEYPAD_9_PAGEUP 0x61
+#define KEY_KEYPAD_0_INSERT 0x62
+#define KEY_KEYPAD_DECIMAL_SEPARATOR_DELETE 0x63
+#define KEY_NONUS_BACK_SLASH_VERTICAL_BAR 0x64
+#define KEY_APPLICATION 0x65
+#define KEY_POWER 0x66
+#define KEY_KEYPAD_EQUAL 0x67
+#define KEY_F13 0x68
+#define KEY_F14 0x69
+#define KEY_F15 0x6A
+#define KEY_F16 0x6B
+#define KEY_F17 0x6C
+#define KEY_F18 0x6D
+#define KEY_F19 0x6E
+#define KEY_F20 0x6F
+#define KEY_F21 0x70
+#define KEY_F22 0x71
+#define KEY_F23 0x72
+#define KEY_F24 0x73
+#define KEY_EXECUTE 0x74
+#define KEY_HELP 0x75
+#define KEY_MENU 0x76
+#define KEY_SELECT 0x77
+#define KEY_STOP 0x78
+#define KEY_AGAIN 0x79
+#define KEY_UNDO 0x7A
+#define KEY_CUT 0x7B
+#define KEY_COPY 0x7C
+#define KEY_PASTE 0x7D
+#define KEY_FIND 0x7E
+#define KEY_MUTE 0x7F
+#define KEY_VOLUME_UP 0x80
+#define KEY_VOLUME_DOWN 0x81
+#define KEY_LOCKING_CAPS_LOCK 0x82
+#define KEY_LOCKING_NUM_LOCK 0x83
+#define KEY_LOCKING_SCROLL_LOCK 0x84
+#define KEY_KEYPAD_COMMA 0x85
+#define KEY_KEYPAD_EQUAL_SIGN 0x86
+#define KEY_INTERNATIONAL1 0x87
+#define KEY_INTERNATIONAL2 0x88
+#define KEY_INTERNATIONAL3 0x89
+#define KEY_INTERNATIONAL4 0x8A
+#define KEY_INTERNATIONAL5 0x8B
+#define KEY_INTERNATIONAL6 0x8C
+#define KEY_INTERNATIONAL7 0x8D
+#define KEY_INTERNATIONAL8 0x8E
+#define KEY_INTERNATIONAL9 0x8F
+#define KEY_LANG1 0x90
+#define KEY_LANG2 0x91
+#define KEY_LANG3 0x92
+#define KEY_LANG4 0x93
+#define KEY_LANG5 0x94
+#define KEY_LANG6 0x95
+#define KEY_LANG7 0x96
+#define KEY_LANG8 0x97
+#define KEY_LANG9 0x98
+#define KEY_ALTERNATE_ERASE 0x99
+#define KEY_SYSREQ 0x9A
+#define KEY_CANCEL 0x9B
+#define KEY_CLEAR 0x9C
+#define KEY_PRIOR 0x9D
+#define KEY_RETURN 0x9E
+#define KEY_SEPARATOR 0x9F
+#define KEY_OUT 0xA0
+#define KEY_OPER 0xA1
+#define KEY_CLEAR_AGAIN 0xA2
+#define KEY_CRSEL 0xA3
+#define KEY_EXSEL 0xA4
+#define KEY_KEYPAD_00 0xB0
+#define KEY_KEYPAD_000 0xB1
+#define KEY_THOUSANDS_SEPARATOR 0xB2
+#define KEY_DECIMAL_SEPARATOR 0xB3
+#define KEY_CURRENCY_UNIT 0xB4
+#define KEY_CURRENCY_SUB_UNIT 0xB5
+#define KEY_KEYPAD_OPARENTHESIS 0xB6
+#define KEY_KEYPAD_CPARENTHESIS 0xB7
+#define KEY_KEYPAD_OBRACE 0xB8
+#define KEY_KEYPAD_CBRACE 0xB9
+#define KEY_KEYPAD_TAB 0xBA
+#define KEY_KEYPAD_BACKSPACE 0xBB
+#define KEY_KEYPAD_A 0xBC
+#define KEY_KEYPAD_B 0xBD
+#define KEY_KEYPAD_C 0xBE
+#define KEY_KEYPAD_D 0xBF
+#define KEY_KEYPAD_E 0xC0
+#define KEY_KEYPAD_F 0xC1
+#define KEY_KEYPAD_XOR 0xC2
+#define KEY_KEYPAD_CARET 0xC3
+#define KEY_KEYPAD_PERCENT 0xC4
+#define KEY_KEYPAD_LESS 0xC5
+#define KEY_KEYPAD_GREATER 0xC6
+#define KEY_KEYPAD_AMPERSAND 0xC7
+#define KEY_KEYPAD_LOGICAL_AND 0xC8
+#define KEY_KEYPAD_VERTICAL_BAR 0xC9
+#define KEY_KEYPAD_LOGIACL_OR 0xCA
+#define KEY_KEYPAD_COLON 0xCB
+#define KEY_KEYPAD_NUMBER_SIGN 0xCC
+#define KEY_KEYPAD_SPACE 0xCD
+#define KEY_KEYPAD_AT 0xCE
+#define KEY_KEYPAD_EXCLAMATION_MARK 0xCF
+#define KEY_KEYPAD_MEMORY_STORE 0xD0
+#define KEY_KEYPAD_MEMORY_RECALL 0xD1
+#define KEY_KEYPAD_MEMORY_CLEAR 0xD2
+#define KEY_KEYPAD_MEMORY_ADD 0xD3
+#define KEY_KEYPAD_MEMORY_SUBTRACT 0xD4
+#define KEY_KEYPAD_MEMORY_MULTIPLY 0xD5
+#define KEY_KEYPAD_MEMORY_DIVIDE 0xD6
+#define KEY_KEYPAD_PLUSMINUS 0xD7
+#define KEY_KEYPAD_CLEAR 0xD8
+#define KEY_KEYPAD_CLEAR_ENTRY 0xD9
+#define KEY_KEYPAD_BINARY 0xDA
+#define KEY_KEYPAD_OCTAL 0xDB
+#define KEY_KEYPAD_DECIMAL 0xDC
+#define KEY_KEYPAD_HEXADECIMAL 0xDD
+#define KEY_LEFTCONTROL 0xE0
+#define KEY_LEFTSHIFT 0xE1
+#define KEY_LEFTALT 0xE2
+#define KEY_LEFT_GUI 0xE3
+#define KEY_RIGHTCONTROL 0xE4
+#define KEY_RIGHTSHIFT 0xE5
+#define KEY_RIGHTALT 0xE6
+#define KEY_RIGHT_GUI 0xE7
+
+typedef enum
+{
+ KBD_LEFT_CTRL = 0x01,
+ KBD_LEFT_SHIFT = 0x02,
+ KBD_LEFT_ALT = 0x04,
+ KBD_LEFT_GUI = 0x08,
+ KBD_RIGHT_CTRL = 0x10,
+ KBD_RIGHT_SHIFT = 0x20,
+ KBD_RIGHT_ALT = 0x40,
+ KBD_RIGHT_GUI = 0x80
+} SpecialKeys;
+
+void key_down(uint8_t* keys, uint8_t key);
+#endif
diff --git a/emb/pastilda/hw/usb_device/ramdisk.c b/emb/pastilda/hw/usb_device/ramdisk.c
new file mode 100644
index 0000000..15ea8a1
--- /dev/null
+++ b/emb/pastilda/hw/usb_device/ramdisk.c
@@ -0,0 +1,160 @@
+#include <string.h>
+#include "ramdisk.h"
+
+#define WBVAL(x) ((x) & 0xFF), (((x) >> 8) & 0xFF)
+#define QBVAL(x) ((x) & 0xFF), (((x) >> 8) & 0xFF),\
+ (((x) >> 16) & 0xFF), (((x) >> 24) & 0xFF)
+
+// filesystem size is 512kB (1024 * SECTOR_SIZE)
+#define SECTOR_COUNT 1024
+#define SECTOR_SIZE 512
+#define BYTES_PER_SECTOR 512
+#define SECTORS_PER_CLUSTER 4
+#define RESERVED_SECTORS 1
+#define FAT_COPIES 2
+#define ROOT_ENTRIES 512
+#define ROOT_ENTRY_LENGTH 32
+#define FILEDATA_START_CLUSTER 3
+#define DATA_REGION_SECTOR (RESERVED_SECTORS + FAT_COPIES + \
+ (ROOT_ENTRIES * ROOT_ENTRY_LENGTH) / BYTES_PER_SECTOR)
+#define FILEDATA_START_SECTOR (DATA_REGION_SECTOR + \
+ (FILEDATA_START_CLUSTER - 2) * SECTORS_PER_CLUSTER)
+
+// filesize is 64kB (128 * SECTOR_SIZE)
+#define FILEDATA_SECTOR_COUNT 128
+
+uint8_t BootSector[] = {
+ 0xEB, 0x3C, 0x90, // code to jump to the bootstrap code
+ 'm', 'k', 'd', 'o', 's', 'f', 's', 0x00, // OEM ID
+ WBVAL(BYTES_PER_SECTOR), // bytes per sector
+ SECTORS_PER_CLUSTER, // sectors per cluster
+ WBVAL(RESERVED_SECTORS), // # of reserved sectors (1 boot sector)
+ FAT_COPIES, // FAT copies (2)
+ WBVAL(ROOT_ENTRIES), // root entries (512)
+ WBVAL(SECTOR_COUNT), // total number of sectors
+ 0xF8, // media descriptor (0xF8 = Fixed disk)
+ 0x01, 0x00, // sectors per FAT (1)
+ 0x20, 0x00, // sectors per track (32)
+ 0x40, 0x00, // number of heads (64)
+ 0x00, 0x00, 0x00, 0x00, // hidden sectors (0)
+ 0x00, 0x00, 0x00, 0x00, // large number of sectors (0)
+ 0x00, // drive number (0)
+ 0x00, // reserved
+ 0x29, // extended boot signature
+ 0x69, 0x17, 0xAD, 0x53, // volume serial number
+ 'R', 'A', 'M', 'D', 'I', 'S', 'K', ' ', ' ', ' ', ' ', // volume label
+ 'F', 'A', 'T', '1', '2', ' ', ' ', ' ' // filesystem type
+};
+
+uint8_t FatSector[] = {
+ 0xF8, 0xFF, 0xFF, 0x00, 0x40, 0x00, 0x05, 0x60, 0x00, 0x07, 0x80, 0x00,
+ 0x09, 0xA0, 0x00, 0x0B, 0xC0, 0x00, 0x0D, 0xE0, 0x00, 0x0F, 0x00, 0x01,
+ 0x11, 0x20, 0x01, 0x13, 0x40, 0x01, 0x15, 0x60, 0x01, 0x17, 0x80, 0x01,
+ 0x19, 0xA0, 0x01, 0x1B, 0xC0, 0x01, 0x1D, 0xE0, 0x01, 0x1F, 0x00, 0x02,
+ 0x21, 0x20, 0x02, 0x23, 0x40, 0x02, 0x25, 0x60, 0x02, 0x27, 0x80, 0x02,
+ 0x29, 0xA0, 0x02, 0x2B, 0xC0, 0x02, 0x2D, 0xE0, 0x02, 0x2F, 0x00, 0x03,
+ 0x31, 0x20, 0x03, 0x33, 0x40, 0x03, 0x35, 0x60, 0x03, 0x37, 0x80, 0x03,
+ 0x39, 0xA0, 0x03, 0x3B, 0xC0, 0x03, 0x3D, 0xE0, 0x03, 0x3F, 0x00, 0x04,
+ 0x41, 0x20, 0x04, 0x43, 0x40, 0x04, 0x45, 0x60, 0x04, 0x47, 0x80, 0x04,
+ 0x49, 0xA0, 0x04, 0x4B, 0xC0, 0x04, 0x4D, 0xE0, 0x04, 0x4F, 0x00, 0x05,
+ 0x51, 0x20, 0x05, 0x53, 0x40, 0x05, 0x55, 0x60, 0x05, 0x57, 0x80, 0x05,
+ 0x59, 0xA0, 0x05, 0x5B, 0xC0, 0x05, 0x5D, 0xE0, 0x05, 0x5F, 0x00, 0x06,
+ 0x61, 0x20, 0x06, 0x63, 0x40, 0x06, 0x65, 0x60, 0x06, 0x67, 0x80, 0x06,
+ 0x69, 0xA0, 0x06, 0x6B, 0xC0, 0x06, 0x6D, 0xE0, 0x06, 0x6F, 0x00, 0x07,
+ 0x71, 0x20, 0x07, 0x73, 0x40, 0x07, 0x75, 0x60, 0x07, 0x77, 0x80, 0x07,
+ 0x79, 0xA0, 0x07, 0x7B, 0xC0, 0x07, 0x7D, 0xE0, 0x07, 0x7F, 0x00, 0x08,
+ 0x81, 0x20, 0x08, 0xFF, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00
+};
+
+uint8_t DirSector[] = {
+ // long filename entry
+ 0x41, // sequence number
+ WBVAL('r'), WBVAL('a'), WBVAL('m'), WBVAL('d'), WBVAL('i'), // five name characters in UTF-16
+ 0x0F, // attributes
+ 0x00, // type
+ 0x00, // checksum of DOS filename (computed in ramdisk_init)
+ WBVAL('s'), WBVAL('k'), WBVAL('.'), WBVAL('d'), WBVAL('a'), WBVAL('t'), // six name characters in UTF-16
+ 0x00, 0x00, // first cluster
+ WBVAL(0), WBVAL(0), // two name characters in UTF-16
+ // actual entry
+ 'R', 'A', 'M', 'D', 'I', 'S', 'K', ' ', // filename
+ 'D', 'A', 'T', // extension
+ 0x20, // attribute byte
+ 0x00, // reserved for Windows NT
+ 0x00, // creation millisecond
+ 0xCE, 0x01, // creation time
+ 0x86, 0x41, // creation date
+ 0x86, 0x41, // last access date
+ 0x00, 0x00, // reserved for FAT32
+ 0xCE, 0x01, // last write time
+ 0x86, 0x41, // last write date
+ WBVAL(FILEDATA_START_CLUSTER), // start cluster
+ QBVAL(FILEDATA_SECTOR_COUNT * SECTOR_SIZE) // file size in bytes
+};
+
+static uint8_t ramdata[FILEDATA_SECTOR_COUNT * SECTOR_SIZE];
+
+int ramdisk_init(void)
+{
+ uint32_t i = 0;
+
+ // compute checksum in the directory entry
+ uint8_t chk = 0;
+ for (i = 32; i < 43; i++) {
+ chk = (((chk & 1) << 7) | ((chk & 0xFE) >> 1)) + DirSector[i];
+ }
+ DirSector[13] = chk;
+
+ // fill ramdata
+ const uint8_t text[] = "USB Mass Storage Class example. ";
+ i = 0;
+ while (i < sizeof(ramdata)) {
+ ramdata[i] = text[i % (sizeof(text) -1)];
+ i++;
+ }
+ return (0);
+}
+
+int ramdisk_read(uint32_t lba, uint8_t *copy_to)
+{
+ memset(copy_to, 0, SECTOR_SIZE);
+ switch (lba) {
+ case 0: // sector 0 is the boot sector
+ memcpy(copy_to, BootSector, sizeof(BootSector));
+ copy_to[SECTOR_SIZE - 2] = 0x55;
+ copy_to[SECTOR_SIZE - 1] = 0xAA;
+ break;
+ case 1: // sector 1 is FAT 1st copy
+ case 2: // sector 2 is FAT 2nd copy
+ memcpy(copy_to, FatSector, sizeof(FatSector));
+ break;
+ case 3: // sector 3 is the directory entry
+ memcpy(copy_to, DirSector, sizeof(DirSector));
+ break;
+ default:
+ // ignore reads outside of the data section
+ if (lba >= FILEDATA_START_SECTOR && lba < FILEDATA_START_SECTOR + FILEDATA_SECTOR_COUNT) {
+ memcpy(copy_to, ramdata + (lba - FILEDATA_START_SECTOR) * SECTOR_SIZE, SECTOR_SIZE);
+ }
+ break;
+ }
+ return (0);
+}
+
+int ramdisk_write(uint32_t lba, const uint8_t *copy_from)
+{
+ (void)lba;
+ (void)copy_from;
+ // ignore writes
+ return (0);
+}
+
+int ramdisk_blocks(void)
+{
+ return (SECTOR_COUNT);
+}
diff --git a/emb/pastilda/hw/usb_device/ramdisk.h b/emb/pastilda/hw/usb_device/ramdisk.h
new file mode 100644
index 0000000..852dc92
--- /dev/null
+++ b/emb/pastilda/hw/usb_device/ramdisk.h
@@ -0,0 +1,14 @@
+#ifndef RAMDISK_H
+#define RAMDISK_H
+
+#include <stdint.h>
+#include <libopencm3/cm3/common.h>
+
+BEGIN_DECLS
+extern int ramdisk_init(void);
+extern int ramdisk_read(uint32_t lba, uint8_t *copy_to);
+extern int ramdisk_write(uint32_t lba, const uint8_t *copy_from);
+extern int ramdisk_blocks(void);
+END_DECLS
+
+#endif
diff --git a/emb/pastilda/hw/usb_device/usbd_composite.cpp b/emb/pastilda/hw/usb_device/usbd_composite.cpp
new file mode 100644
index 0000000..2c2311a
--- /dev/null
+++ b/emb/pastilda/hw/usb_device/usbd_composite.cpp
@@ -0,0 +1,136 @@
+#include "usbd_composite.h"
+
+using namespace GPIO_CPP_Extension;
+
+USB_composite *usb_pointer;
+USB_composite::USB_composite()
+{
+ usb_pointer = this;
+ descriptors = new UsbCompositeDescriptors();
+
+ GPIO_ext uf_p(PA11);
+ GPIO_ext uf_m(PA12);
+
+ uf_p.mode_setup(Mode::ALTERNATE_FUNCTION, PullMode::NO_PULL);
+ uf_m.mode_setup(Mode::ALTERNATE_FUNCTION, PullMode::NO_PULL);
+
+ uf_p.set_af(AF_Number::AF10);
+ uf_m.set_af(AF_Number::AF10);
+
+ my_usb_device = usbd_init(&otgfs_usb_driver, &(descriptors->dev),
+ &(descriptors->config_descr), (const char**)descriptors->usb_strings, 3,
+ usbd_control_buffer, sizeof(usbd_control_buffer));
+
+ usbd_register_set_config_callback(my_usb_device, USB_set_config_callback);
+ nvic_enable_irq(NVIC_OTG_FS_IRQ);
+
+ ramdisk_init();
+
+ usb_msc_init(my_usb_device, Endpoint::E_MASS_STORAGE_IN, 64, Endpoint::E_MASS_STORAGE_OUT, 64,
+ "ThirdPin", "Pastilda", "0.00", ramdisk_blocks(), ramdisk_read, ramdisk_write);
+}
+
+void USB_composite::usb_send_packet(const void *buf, int len)
+{
+ while(usbd_ep_write_packet(my_usb_device, 0x81, buf, len) == 0);
+}
+
+void USB_OTG_IRQ()
+{
+ usbd_poll(usb_pointer->my_usb_device);
+ usb_pointer->last_usb_request_time = get_counter_ms();
+}
+
+int USB_composite::hid_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
+ void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req))
+{
+ (void)complete;
+ (void)usbd_dev;
+
+ if ((req->bmRequestType & USB_REQ_TYPE_DIRECTION) == USB_REQ_TYPE_IN)
+ {
+ if ((req->bmRequestType & USB_REQ_TYPE_TYPE) == USB_REQ_TYPE_STANDARD)
+ {
+ if (req->bRequest == USB_REQ_GET_DESCRIPTOR)
+ {
+ if (req->wValue == 0x2200)
+ {
+ *buf = (uint8_t *)descriptors->keyboard_report_descriptor;
+ *len = sizeof(descriptors->keyboard_report_descriptor);
+ return (USBD_REQ_HANDLED);
+ }
+ else if (req->wValue == 0x2100)
+ {
+ *buf = (uint8_t *)&descriptors->keyboard_hid_function;
+ *len = sizeof(descriptors->keyboard_hid_function);
+ return (USBD_REQ_HANDLED);
+ }
+ return (USBD_REQ_NOTSUPP);
+ }
+ }
+ else if ((req->bmRequestType & USB_REQ_TYPE_TYPE) == USB_REQ_TYPE_CLASS)
+ {
+ if (req->bRequest == HidRequest::GET_REPORT)
+ {
+ *buf = (uint8_t*)&boot_key_report;
+ *len = sizeof(boot_key_report);
+ return (USBD_REQ_HANDLED);
+ }
+ else if (req->bRequest == HidRequest::GET_IDLE)
+ {
+ *buf = &keyboard_idle;
+ *len = sizeof(keyboard_idle);
+ return (USBD_REQ_HANDLED);
+ }
+ else if (req->bRequest == HidRequest::GET_PROTOCOL)
+ {
+ *buf = &keyboard_protocol;
+ *len = sizeof(keyboard_protocol);
+ return (USBD_REQ_HANDLED);
+ }
+ return (USBD_REQ_NOTSUPP);
+ }
+ }
+
+ else
+ {
+ if ((req->bmRequestType & USB_REQ_TYPE_TYPE) == USB_REQ_TYPE_CLASS)
+ {
+ if (req->bRequest == HidRequest::SET_REPORT)
+ {
+ if (*len == 1)
+ {
+ keyboard_leds = (*buf)[0];
+ }
+ return (USBD_REQ_HANDLED);
+ }
+ else if (req->bRequest == HidRequest::SET_IDLE)
+ {
+ keyboard_idle = req->wValue >> 8;
+ return (USBD_REQ_HANDLED);
+ }
+ else if (req->bRequest == HidRequest::SET_PROTOCOL)
+ {
+ keyboard_protocol = req->wValue;
+ return (USBD_REQ_HANDLED);
+ }
+ }
+ return (USBD_REQ_NOTSUPP);
+ }
+
+ return (USBD_REQ_NEXT_CALLBACK);
+}
+
+int USB_control_callback(usbd_device *usbd_dev,
+ struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
+ usbd_control_complete_callback *complete)
+{
+ return( usb_pointer->hid_control_request(usbd_dev, req, buf, len, complete));
+}
+
+
+void USB_set_config_callback(usbd_device *usbd_dev,
+ uint16_t wValue)
+{
+ usb_pointer->hid_set_config(usbd_dev, wValue) ;
+}
diff --git a/emb/pastilda/hw/usb_device/usbd_composite.h b/emb/pastilda/hw/usb_device/usbd_composite.h
new file mode 100644
index 0000000..b40fab8
--- /dev/null
+++ b/emb/pastilda/hw/usb_device/usbd_composite.h
@@ -0,0 +1,60 @@
+#ifndef USB_MSC_H
+#define USB_MSC_H
+
+extern "C"
+{
+#include "ramdisk.h"
+}
+#include "usbd_composite_desc.h"
+#include "systick_ext.h"
+#include "gpio_ext.h"
+
+#define USB_OTG_IRQ otg_fs_isr
+extern "C" void USB_OTG_IRQ();
+
+int USB_control_callback(usbd_device *usbd_dev, struct usb_setup_data *req,
+ uint8_t **buf, uint16_t *len, usbd_control_complete_callback *complete);
+
+void USB_set_config_callback(usbd_device *usbd_dev, uint16_t wValue);
+
+static uint8_t keyboard_protocol = 1;
+static uint8_t keyboard_idle = 0;
+static uint8_t keyboard_leds = 0;
+
+static struct {
+ uint8_t modifiers;
+ uint8_t reserved;
+ uint8_t keys[6];
+} boot_key_report;
+
+class USB_composite
+{
+public:
+ uint8_t usbd_control_buffer[500];
+ UsbCompositeDescriptors *descriptors;
+ uint8_t usb_ready = 0;
+ volatile uint32_t last_usb_request_time;
+ usbd_device *my_usb_device;
+
+ USB_composite();
+
+ void usb_send_packet(const void *buf, int len);
+
+ void usb_poll()
+ {
+ usbd_poll(my_usb_device);
+ }
+
+ int hid_control_request(usbd_device *usbd_dev, struct usb_setup_data *req, uint8_t **buf, uint16_t *len,
+ void (**complete)(usbd_device *usbd_dev, struct usb_setup_data *req));
+
+ void hid_set_config(usbd_device *usbd_dev, uint16_t wValue)
+ {
+ (void)wValue;
+ (void)usbd_dev;
+
+ usbd_ep_setup(usbd_dev, Endpoint::E_KEYBOARD, USB_ENDPOINT_ATTR_INTERRUPT, 8, 0);
+ usbd_register_control_callback(usbd_dev, USB_REQ_TYPE_INTERFACE, USB_REQ_TYPE_RECIPIENT, USB_control_callback );
+ }
+};
+#endif
diff --git a/emb/pastilda/hw/usb_device/usbd_composite_desc.cpp b/emb/pastilda/hw/usb_device/usbd_composite_desc.cpp
new file mode 100644
index 0000000..cae2c24
--- /dev/null
+++ b/emb/pastilda/hw/usb_device/usbd_composite_desc.cpp
@@ -0,0 +1,11 @@
+#include "usbd_composite_desc.h"
+
+constexpr uint8_t UsbCompositeDescriptors::keyboard_report_descriptor[];
+constexpr UsbCompositeDescriptors::type_hid_function UsbCompositeDescriptors::keyboard_hid_function;
+constexpr struct usb_device_descriptor UsbCompositeDescriptors::dev;
+constexpr struct usb_endpoint_descriptor UsbCompositeDescriptors::hid_endpoint;
+constexpr struct usb_endpoint_descriptor UsbCompositeDescriptors::msc_endpoint[];
+constexpr struct usb_interface_descriptor UsbCompositeDescriptors::iface[];
+constexpr struct usb_config_descriptor::usb_interface UsbCompositeDescriptors::ifaces[];
+constexpr struct usb_config_descriptor UsbCompositeDescriptors::config_descr;
+constexpr char UsbCompositeDescriptors::usb_strings[][30];
diff --git a/emb/pastilda/hw/usb_device/usbd_composite_desc.h b/emb/pastilda/hw/usb_device/usbd_composite_desc.h
new file mode 100644
index 0000000..d3d293f
--- /dev/null
+++ b/emb/pastilda/hw/usb_device/usbd_composite_desc.h
@@ -0,0 +1,162 @@
+#ifndef USB_COMPOSITE_DESCRIPTORS
+#define USB_COMPOSITE_DESCRIPTORS
+
+extern "C"
+{
+#include <libopencm3/usb/usbd.h>
+#include <libopencm3/usb/hid.h>
+#include <libopencm3/usb/msc.h>
+}
+
+typedef enum {
+ I_KEYBOARD = 0,
+ I_MASS_STORAGE = 1
+} Interface;
+
+typedef enum : uint8_t {
+ E_KEYBOARD = 0x81,
+ E_MASS_STORAGE_IN = 0x83,
+ E_MASS_STORAGE_OUT = 0x03
+} Endpoint;
+
+typedef enum {
+ GET_REPORT = 1,
+ GET_IDLE = 2,
+ GET_PROTOCOL = 3,
+ SET_REPORT = 9,
+ SET_IDLE = 10,
+ SET_PROTOCOL = 11,
+} HidRequest;
+
+class UsbCompositeDescriptors
+{
+public:
+ static constexpr uint8_t keyboard_report_descriptor[] =
+ {
+ 0x05, 0x01, 0x09, 0x06, 0xA1, 0x01, 0x05, 0x07, 0x19, 0xE0, 0x29, 0xE7, 0x15, 0x00, 0x25, 0x01,
+ 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08, 0x81, 0x01, 0x95, 0x03, 0x75, 0x01,
+ 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91, 0x02, 0x95, 0x05, 0x75, 0x01, 0x91, 0x01, 0x95, 0x06,
+ 0x75, 0x08, 0x15, 0x00, 0x26, 0xFF, 0x00, 0x05, 0x07, 0x19, 0x00, 0x2A, 0xFF, 0x00, 0x81, 0x00,
+ 0xC0
+ };
+
+ static constexpr char usb_strings[][30] =
+ {
+ "Third pin",
+ "Composite Device",
+ "Pastilda"
+ };
+
+ static constexpr struct usb_device_descriptor dev =
+ {
+ USB_DT_DEVICE_SIZE,
+ USB_DT_DEVICE,
+ 0x0110,
+ 0x0,
+ 0x00, 0x00, 64,
+ 0x0483, 0x5741, 0x0200,
+ 1, 2, 3, 1
+ };
+
+ typedef struct __attribute__((packed))
+ {
+ struct usb_hid_descriptor hid_descriptor;
+ struct
+ {
+ uint8_t bReportDescriptorType;
+ uint16_t wDescriptorLength;
+ } __attribute__((packed)) hid_report;
+ } type_hid_function;
+
+ static constexpr type_hid_function keyboard_hid_function =
+ {
+ {
+ 9,
+ USB_DT_HID,
+ 0x0111, 0, 1
+ },
+
+ {
+ USB_DT_REPORT,
+ sizeof(keyboard_report_descriptor)
+ }
+ };
+
+ static constexpr struct usb_endpoint_descriptor hid_endpoint =
+ {
+ USB_DT_ENDPOINT_SIZE,
+ USB_DT_ENDPOINT, Endpoint::E_KEYBOARD,
+ USB_ENDPOINT_ATTR_INTERRUPT,
+ 64, 0x20
+ };
+
+ static constexpr struct usb_endpoint_descriptor msc_endpoint[] =
+ {
+ {
+ USB_DT_ENDPOINT_SIZE,
+ USB_DT_ENDPOINT,
+ Endpoint::E_MASS_STORAGE_IN, USB_ENDPOINT_ATTR_BULK,
+ 64, 0
+ },
+
+ {
+ USB_DT_ENDPOINT_SIZE,
+ USB_DT_ENDPOINT,
+ Endpoint::E_MASS_STORAGE_OUT, USB_ENDPOINT_ATTR_BULK,
+ 64, 0
+ }
+ };
+
+ static constexpr struct usb_interface_descriptor iface[] =
+ {
+ {
+ USB_DT_INTERFACE_SIZE,
+ USB_DT_INTERFACE,
+ Interface::I_KEYBOARD, 0, 1,
+ USB_CLASS_HID,
+ 1, 1, 0,
+ &hid_endpoint, &keyboard_hid_function,
+ sizeof(keyboard_hid_function)
+ },
+
+ {
+ USB_DT_INTERFACE_SIZE,
+ USB_DT_INTERFACE,
+ Interface::I_MASS_STORAGE, 0, 2,
+ USB_CLASS_MSC,
+ USB_MSC_SUBCLASS_SCSI, USB_MSC_PROTOCOL_BBB, 0x00,
+ msc_endpoint, 0, 0
+ },
+
+ };
+ //array
+ static constexpr struct usb_config_descriptor::usb_interface ifaces[]
+ {
+ {
+ (uint8_t *)0,
+ 1,
+ (usb_iface_assoc_descriptor*)0,
+ &iface[Interface::I_KEYBOARD]
+ },
+
+ {
+ (uint8_t *)0,
+ 1,
+ (usb_iface_assoc_descriptor*)0,
+ &iface[Interface::I_MASS_STORAGE]
+ },
+
+ };
+
+ static constexpr struct usb_config_descriptor config_descr =
+ {
+ USB_DT_CONFIGURATION_SIZE,
+ USB_DT_CONFIGURATION,
+ 0,
+ 2, 1, 0, 0x80, 0x50,
+ ifaces
+ };
+
+ UsbCompositeDescriptors() {}
+};
+#endif
diff --git a/emb/pastilda/hw/usb_host/usbh_host.cpp b/emb/pastilda/hw/usb_host/usbh_host.cpp
new file mode 100644
index 0000000..3b92b81
--- /dev/null
+++ b/emb/pastilda/hw/usb_host/usbh_host.cpp
@@ -0,0 +1,82 @@
+#include "usbh_host.h"
+
+constexpr hid_kbd_config_t USB_host::kbd_config;
+constexpr usbh_dev_driver_t* USB_host::device_drivers[];
+
+USB_host *usb_host_pointer;
+USB_host::USB_host(redirect _redirect_callback, control_interception _control_interception_callback)
+{
+ usb_host_pointer = this;
+ redirect_callback = _redirect_callback;
+ control_interception_callback = _control_interception_callback;
+
+ timer_setup();
+ oth_hs_setup();
+ usart_setup();
+
+ hid_kbd_driver_init(&kbd_config);
+ usbh_init(usbh_lld_stm32f4_drivers, device_drivers);
+
+ LOG_PRINTF("USB init complete\n");
+ LOG_FLUSH();
+}
+
+void USB_host::poll()
+{
+ usbh_poll(get_time_us());
+ LOG_FLUSH();
+ delay_ms(1);
+}
+
+void USB_host::kbd_in_message_handler(uint8_t data_len, const uint8_t *data)
+{
+ if ((data[0] == 0x03) && data[2] == 0x35) {
+ control_interception_callback();
+ }
+ else {
+ redirect_callback((uint8_t*)data, data_len);
+ }
+}
+
+void USB_host::timer_setup()
+{
+ _timer = new TIMER_ext(USB_HOST_TIMER_NUMBER);
+ _timer->set_prescaler_value(USB_HOST_TIMER_PRESCALER);
+ _timer->set_autoreload_value(USB_HOST_TIMER_PERIOD);
+ _timer->enable_counter();
+}
+
+void USB_host::oth_hs_setup()
+{
+ GPIO_ext uf_p(PB15);
+ GPIO_ext uf_m(PB14);
+
+ uf_p.mode_setup(Mode::ALTERNATE_FUNCTION, PullMode::NO_PULL);
+ uf_m.mode_setup(Mode::ALTERNATE_FUNCTION, PullMode::NO_PULL);
+
+ uf_p.set_af(AF_Number::AF12);
+ uf_m.set_af(AF_Number::AF12);
+}
+
+void USB_host::usart_setup()
+{
+ GPIO_ext uart_rx(PC6);
+ GPIO_ext uart_tx(PC7);
+
+ uart_rx.mode_setup(Mode::ALTERNATE_FUNCTION, PullMode::NO_PULL);
+ uart_tx.mode_setup(Mode::ALTERNATE_FUNCTION, PullMode::NO_PULL);
+
+ uart_rx.set_af(AF_Number::AF8);
+ uart_tx.set_af(AF_Number::AF8);
+
+#ifdef USART_DEBUG
+ usart_init(USART6, 921600);
+#endif
+}
+
+//convert to 1MHz less precise timer value
+//units: microseconds
+uint32_t USB_host::get_time_us()
+{
+ return ((_timer->get_counter_value()) * 100);
+}
diff --git a/emb/pastilda/hw/usb_host/usbh_host.h b/emb/pastilda/hw/usb_host/usbh_host.h
new file mode 100644
index 0000000..ff78a18
--- /dev/null
+++ b/emb/pastilda/hw/usb_host/usbh_host.h
@@ -0,0 +1,51 @@
+#ifndef USBH_HOST_H
+#define USBH_HOST_H
+
+#include <string.h>
+#include <libopencm3/cm3/common.h>
+#include <libopencm3/stm32/usart.h>
+#include "timer_ext.h"
+#include "gpio_ext.h"
+#include "systick_ext.h"
+BEGIN_DECLS
+#include "usart_helpers.h"
+#include "usbh_hubbed.h"
+#include "usbh_driver_hid_kbd.h"
+#include "usbh_lld_stm32f4.h"
+END_DECLS
+
+using namespace TIMER_CPP_Extension;
+using namespace GPIO_CPP_Extension;
+
+constexpr uint8_t USB_HOST_TIMER_NUMBER = 6;
+constexpr uint16_t USB_HOST_TIMER_PRESCALER = (8400 - 1);
+constexpr uint16_t USB_HOST_TIMER_PERIOD = (65535);
+
+typedef void (*redirect)(uint8_t *data, uint8_t len);
+typedef void (*control_interception)();
+
+static redirect redirect_callback;
+static control_interception control_interception_callback;
+
+class USB_host
+{
+public:
+ USB_host(redirect redirect_callback, control_interception control_interception_callback);
+ void poll();
+
+ static void kbd_in_message_handler(uint8_t data_len, const uint8_t *data);
+
+ static constexpr hid_kbd_config_t kbd_config = { &kbd_in_message_handler };
+ static constexpr usbh_dev_driver_t *device_drivers[] =
+ {
+ (usbh_dev_driver_t *)&usbh_hid_kbd_driver
+ };
+
+private:
+ TIMER_ext *_timer;
+ void timer_setup();
+ uint32_t get_time_us();
+ void oth_hs_setup();
+ void usart_setup();
+};
+#endif
diff --git a/emb/pastilda/lib/libusbhost/usbh_config.h b/emb/pastilda/lib/libusbhost/usbh_config.h
new file mode 100644
index 0000000..4fa38cb
--- /dev/null
+++ b/emb/pastilda/lib/libusbhost/usbh_config.h
@@ -0,0 +1,62 @@
+/*
+ * This file is part of the libusbhost library
+ * hosted at http://github.com/libusbhost/libusbhost
+ *
+ * Copyright (C) 2015 Amir Hammad <amir.hammad@hotmail.com>
+ *
+ *
+ * libusbhost is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef USBH_CONFIG_
+#define USBH_CONFIG_
+
+
+
+// Max devices per hub
+#define USBH_HUB_MAX_DEVICES (8)
+
+// Max number of hub instancies
+#define USBH_MAX_HUBS (2)
+
+// Max devices
+#define USBH_MAX_DEVICES (15)
+
+// Min: 128
+// Set this wisely
+#define BUFFER_ONE_BYTES (2048)
+
+// MOUSE
+#define USBH_HID_MOUSE_MAX_DEVICES (2)
+
+#define USBH_HID_MOUSE_BUFFER (32)
+
+// MIDI
+// Maximal number of midi devices connected to whatever hub
+#define USBH_AC_MIDI_MAX_DEVICES (4)
+
+#define USBH_AC_MIDI_BUFFER (64)
+
+// Gamepad XBOX
+#define USBH_GP_XBOX_MAX_DEVICES (2)
+
+#define USBH_GP_XBOX_BUFFER (32)
+
+/* Sanity checks */
+#if (USBH_MAX_DEVICES > 127)
+#error USBH_MAX_DEVICES > 127
+#endif
+
+#endif
diff --git a/emb/pastilda/lib/libusbhost/usbh_device_driver.h b/emb/pastilda/lib/libusbhost/usbh_device_driver.h
new file mode 100644
index 0000000..137b39b
--- /dev/null
+++ b/emb/pastilda/lib/libusbhost/usbh_device_driver.h
@@ -0,0 +1,131 @@
+/*
+ * This file is part of the libusbhost library
+ * hosted at http://github.com/libusbhost/libusbhost
+ *
+ * Copyright (C) 2015 Amir Hammad <amir.hammad@hotmail.com>
+ *
+ *
+ * libusbhost is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef USBH_DEVICE_DRIVER_
+#define USBH_DEVICE_DRIVER_
+
+#include "usbh_config.h"
+#include "usbh_hubbed.h"
+
+#include <stdint.h>
+
+BEGIN_DECLS
+
+#define USBH_EPTYP_CONTROL (0)
+#define USBH_EPTYP_ISOCHRONOUS (1)
+#define USBH_EPTYP_BULK (2)
+#define USBH_EPTYP_INTERRUPT (3)
+
+#define USBH_SPEED_FULL (0)
+#define USBH_SPEED_LOW (1)
+#define USBH_SPEED_HIGH (2)
+
+
+enum USBH_PACKET_CALLBACK_STATUS {
+ USBH_PACKET_CALLBACK_STATUS_OK = 0,
+ USBH_PACKET_CALLBACK_STATUS_ERRSIZ = 1,
+ USBH_PACKET_CALLBACK_STATUS_EAGAIN = 2, // -- TODO: automatic handling of transmit errors 3xTXERR->FATAL
+ USBH_PACKET_CALLBACK_STATUS_EFATAL = 3
+};
+
+enum USBH_POLL_STATUS {
+ USBH_POLL_STATUS_NONE,
+ USBH_POLL_STATUS_DEVICE_CONNECTED,
+ USBH_POLL_STATUS_DEVICE_DISCONNECTED
+};
+
+struct _usbh_device {
+ uint16_t packet_size_max0;
+ int8_t address;
+ uint8_t speed; // (USBH_SPEED_*)
+ uint8_t state; // for enumeration purposes
+ uint8_t toggle0;
+ const usbh_dev_driver_t *drv;
+ void *drvdata;
+ const void *lld;
+};
+typedef struct _usbh_device usbh_device_t;
+
+struct _usbh_packet_callback_data {
+ enum USBH_PACKET_CALLBACK_STATUS status;
+ uint32_t transferred_length;
+};
+typedef struct _usbh_packet_callback_data usbh_packet_callback_data_t;
+
+typedef void (*usbh_packet_callback_t)(usbh_device_t *dev, usbh_packet_callback_data_t status);
+
+struct _usbh_packet {
+ void *data; // Pointer to data
+ uint16_t datalen; // Data length 0..1023
+ int8_t address; // Device address
+ uint8_t endpoint_type; // Endpoint type (see USBH_EPTYP_*)
+ uint8_t endpoint_address; // Endpoint number 0..15
+ uint16_t endpoint_size_max; // Max packet size for an endpoint
+ uint8_t speed; // (USBH_SPEED_*)
+ uint8_t *toggle;
+ usbh_packet_callback_t callback;
+ void *callback_arg;
+};
+typedef struct _usbh_packet usbh_packet_t;
+
+struct _usbh_driver {
+ void (*init)(void *drvdata);
+ void (*write)(void *drvdata, const usbh_packet_t *packet);
+ void (*read)(void *drvdata, usbh_packet_t *packet);
+ enum USBH_POLL_STATUS (*poll)(void *drvdata, uint32_t time_curr_us);
+ uint8_t (*root_speed)(void *drvdata);
+
+ // Pointer to Low-level driver data
+ void *driver_data;
+};
+typedef struct _usbh_driver usbh_driver_t;
+
+struct _usbh_generic_data {
+ usbh_device_t usbh_device[USBH_MAX_DEVICES];
+ uint8_t usbh_buffer[BUFFER_ONE_BYTES];
+};
+typedef struct _usbh_generic_data usbh_generic_data_t;
+
+
+#define ERROR(arg) LOG_PRINTF("UNHANDLED_ERROR %d: file: %s, line: %d",\
+ arg, __FILE__, __LINE__)
+
+
+/// Hub related functions
+
+usbh_device_t *usbh_get_free_device(const usbh_device_t *dev);
+bool usbh_enum_available(void);
+void device_enumeration_start(usbh_device_t *dev);
+
+/// All devices functions
+
+///
+void usbh_read(usbh_device_t *dev, usbh_packet_t *packet);
+void usbh_write(usbh_device_t *dev, const usbh_packet_t *packet);
+/// Helper functions
+void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev);
+void device_xfer_control_write(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev);
+
+
+END_DECLS
+
+#endif
diff --git a/emb/pastilda/lib/libusbhost/usbh_driver_hid_kbd.c b/emb/pastilda/lib/libusbhost/usbh_driver_hid_kbd.c
new file mode 100644
index 0000000..29d5008
--- /dev/null
+++ b/emb/pastilda/lib/libusbhost/usbh_driver_hid_kbd.c
@@ -0,0 +1,257 @@
+#include "usbh_hubbed.h"
+#include "driver/usbh_device_driver.h"
+#include "usbh_driver_hid_kbd.h"
+#include "usart_helpers.h"
+
+#include <libopencm3/usb/usbstd.h>
+
+enum STATES {
+ STATE_INACTIVE,
+ STATE_READING_COMPLETE,
+ STATE_READING_REQUEST,
+ STATE_SET_CONFIGURATION_REQUEST,
+ STATE_SET_CONFIGURATION_EMPTY_READ,
+ STATE_SET_CONFIGURATION_COMPLETE
+};
+
+struct _hid_kbd_device {
+ usbh_device_t *usbh_device;
+ uint8_t buffer[USBH_HID_MOUSE_BUFFER];
+ uint16_t endpoint_in_maxpacketsize;
+ uint8_t endpoint_in_address;
+ enum STATES state_next;
+ uint8_t endpoint_in_toggle;
+ uint8_t device_id;
+ uint8_t configuration_value;
+};
+typedef struct _hid_kbd_device hid_kbd_device_t;
+
+static hid_kbd_device_t kbd_device[USBH_HID_MOUSE_MAX_DEVICES];
+static const hid_kbd_config_t *kbd_config;
+
+#include <stdint.h>
+
+static bool initialized = false;
+
+void hid_kbd_driver_init(const hid_kbd_config_t *config)
+{
+ uint32_t i;
+ initialized = true;
+
+ kbd_config = config;
+ for (i = 0; i < USBH_HID_MOUSE_MAX_DEVICES; i++) {
+ kbd_device[i].state_next = STATE_INACTIVE;
+ }
+}
+
+static void *init(void *usbh_dev)
+{
+ if (!initialized) {
+ LOG_PRINTF("\n%s/%d : driver not initialized\r\n", __FILE__, __LINE__);
+ return (0);
+ }
+
+ uint32_t i;
+ hid_kbd_device_t *drvdata = 0;
+
+ // find free data space for mouse device
+ for (i = 0; i < USBH_HID_MOUSE_MAX_DEVICES; i++) {
+ if (kbd_device[i].state_next == STATE_INACTIVE) {
+ drvdata = &kbd_device[i];
+ drvdata->device_id = i;
+ drvdata->endpoint_in_address = 0;
+ drvdata->endpoint_in_toggle = 0;
+ drvdata->usbh_device = (usbh_device_t *)usbh_dev;
+ break;
+ }
+ }
+
+ return (drvdata);
+}
+
+static bool analyze_descriptor(void *drvdata, void *descriptor)
+{
+ hid_kbd_device_t *kbd = (hid_kbd_device_t *)drvdata;
+ uint8_t desc_type = ((uint8_t *)descriptor)[1];
+ switch (desc_type) {
+ case USB_DT_CONFIGURATION:
+ {
+ struct usb_config_descriptor *cfg = (struct usb_config_descriptor*)descriptor;
+ kbd->configuration_value = cfg->bConfigurationValue;
+ }
+ break;
+ case USB_DT_DEVICE:
+ break;
+ case USB_DT_INTERFACE:
+ break;
+ case USB_DT_ENDPOINT:
+ {
+ struct usb_endpoint_descriptor *ep = (struct usb_endpoint_descriptor*)descriptor;
+ if ((ep->bmAttributes&0x03) == USB_ENDPOINT_ATTR_INTERRUPT) {
+ uint8_t epaddr = ep->bEndpointAddress;
+ if (epaddr & (1<<7)) {
+ kbd->endpoint_in_address = epaddr&0x7f;
+ if (ep->wMaxPacketSize < USBH_HID_MOUSE_BUFFER) {
+ kbd->endpoint_in_maxpacketsize = ep->wMaxPacketSize;
+ } else {
+ kbd->endpoint_in_maxpacketsize = USBH_HID_MOUSE_BUFFER;
+ }
+ }
+
+ if (kbd->endpoint_in_address) {
+ kbd->state_next = STATE_SET_CONFIGURATION_REQUEST;
+ return (true);
+ }
+ }
+ }
+ break;
+ // TODO Class Specific descriptors
+ default:
+ break;
+ }
+ return (false);
+}
+
+static void event(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
+{
+ hid_kbd_device_t *kbd = (hid_kbd_device_t *)dev->drvdata;
+ switch (kbd->state_next) {
+ case STATE_READING_COMPLETE:
+ {
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ kbd->state_next = STATE_READING_REQUEST;
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ ERROR(cb_data.status);
+ kbd->state_next = STATE_INACTIVE;
+ break;
+ }
+ }
+ break;
+
+ case STATE_SET_CONFIGURATION_EMPTY_READ:
+ {
+ LOG_PRINTF("|empty packet read|");
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ kbd->state_next = STATE_SET_CONFIGURATION_COMPLETE;
+ device_xfer_control_read(0, 0, event, dev);
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ ERROR(cb_data.status);
+ kbd->state_next = STATE_INACTIVE;
+ break;
+ }
+ }
+ break;
+ case STATE_SET_CONFIGURATION_COMPLETE: // Configured
+ {
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ kbd->state_next = STATE_READING_REQUEST;
+ kbd->endpoint_in_toggle = 0;
+ LOG_PRINTF("\nKEYBOARD CONFIGURED\n");
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ ERROR(cb_data.status);
+ kbd->state_next = STATE_INACTIVE;
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void read_kbd_in(void *drvdata)
+{
+ hid_kbd_device_t *kbd = (hid_kbd_device_t *)drvdata;
+ usbh_packet_t packet;
+
+ packet.address = kbd->usbh_device->address;
+ packet.data = &kbd->buffer[0];
+ packet.datalen = kbd->endpoint_in_maxpacketsize;
+ packet.endpoint_address = kbd->endpoint_in_address;
+ packet.endpoint_size_max = kbd->endpoint_in_maxpacketsize;
+ packet.endpoint_type = USBH_EPTYP_INTERRUPT;
+ packet.speed = kbd->usbh_device->speed;
+ packet.callback = event;
+ packet.callback_arg = kbd->usbh_device;
+ packet.toggle = &kbd->endpoint_in_toggle;
+
+ kbd->state_next = STATE_READING_COMPLETE;
+ usbh_read(kbd->usbh_device, &packet);
+ kbd_config->kbd_in_message_handler(packet.datalen, packet.data);
+}
+
+static void poll(void *drvdata, uint32_t time_curr_us)
+{
+ (void)time_curr_us;
+
+ hid_kbd_device_t *kbd = (hid_kbd_device_t *)drvdata;
+ usbh_device_t *dev = kbd->usbh_device;
+ switch (kbd->state_next) {
+ case STATE_READING_REQUEST:
+ {
+ read_kbd_in(drvdata);
+ }
+ break;
+
+ case STATE_SET_CONFIGURATION_REQUEST:
+ {
+ struct usb_setup_data setup_data;
+
+ setup_data.bmRequestType = 0b00000000;
+ setup_data.bRequest = USB_REQ_SET_CONFIGURATION;
+ setup_data.wValue = kbd->configuration_value;
+ setup_data.wIndex = 0;
+ setup_data.wLength = 0;
+
+ kbd->state_next = STATE_SET_CONFIGURATION_EMPTY_READ;
+
+ device_xfer_control_write(&setup_data, sizeof(setup_data), event, dev);
+ }
+ break;
+
+ default:
+ // do nothing - probably transfer is in progress
+ break;
+ }
+}
+
+static void remove(void *drvdata)
+{
+ hid_kbd_device_t *kbd = (hid_kbd_device_t *)drvdata;
+ kbd->state_next = STATE_INACTIVE;
+ kbd->endpoint_in_address = 0;
+}
+
+static const usbh_dev_driver_info_t driver_info = {
+ .deviceClass = -1,
+ .deviceSubClass = -1,
+ .deviceProtocol = -1,
+ .idVendor = -1,
+ .idProduct = -1,
+ .ifaceClass = 0x03,
+ .ifaceSubClass = 1, //-1
+ .ifaceProtocol = 0x01 //0x02
+};
+
+const usbh_dev_driver_t usbh_hid_kbd_driver = {
+ .init = init,
+ .analyze_descriptor = analyze_descriptor,
+ .poll = poll,
+ .remove = remove,
+ .info = &driver_info
+};
diff --git a/emb/pastilda/lib/libusbhost/usbh_driver_hid_kbd.h b/emb/pastilda/lib/libusbhost/usbh_driver_hid_kbd.h
new file mode 100644
index 0000000..43f29ac
--- /dev/null
+++ b/emb/pastilda/lib/libusbhost/usbh_driver_hid_kbd.h
@@ -0,0 +1,22 @@
+#ifndef USBH_DRIVER_HID_KBD
+#define USBH_DRIVER_HID_KBD
+
+#include "usbh_hubbed.h"
+#include <stdint.h>
+
+BEGIN_DECLS
+
+typedef void (*t_read_kbd)(void* data, uint8_t data_len);
+
+struct _hid_kbd_config {
+ void (*kbd_in_message_handler)(uint8_t device_id, const uint8_t *data);
+};
+typedef struct _hid_kbd_config hid_kbd_config_t;
+
+void hid_kbd_driver_init(const hid_kbd_config_t *config);
+
+extern const usbh_dev_driver_t usbh_hid_kbd_driver;
+
+END_DECLS
+
+#endif
diff --git a/emb/pastilda/lib/libusbhost/usbh_hubbed.c b/emb/pastilda/lib/libusbhost/usbh_hubbed.c
new file mode 100644
index 0000000..1921842
--- /dev/null
+++ b/emb/pastilda/lib/libusbhost/usbh_hubbed.c
@@ -0,0 +1,611 @@
+/*
+ * This file is part of the libusbhost library
+ * hosted at http://github.com/libusbhost/libusbhost
+ *
+ * Copyright (C) 2015 Amir Hammad <amir.hammad@hotmail.com>
+ *
+ *
+ * libusbhost is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "usbh_config.h"
+#include "usbh_lld_stm32f4.h"
+#include "driver/usbh_device_driver.h"
+#include "usart_helpers.h"
+
+#include <libopencm3/stm32/gpio.h>
+#include <libopencm3/usb/usbstd.h>
+
+static struct {
+ bool enumeration_run;
+ const usbh_driver_t * const *lld_drivers;
+ const usbh_dev_driver_t * const *dev_drivers;
+ int8_t address_temporary;
+} usbh_data = {0};
+
+static void set_enumeration(void)
+{
+ usbh_data.enumeration_run = true;
+}
+
+static void reset_enumeration(void)
+{
+ usbh_data.enumeration_run = false;
+}
+
+static bool enumeration(void)
+{
+ return usbh_data.enumeration_run;
+}
+
+/**
+ *
+ */
+static const usbh_dev_driver_t *find_driver(const usbh_dev_driver_info_t * device_info)
+{
+
+#define CHECK_PARTIAL_COMPATIBILITY(what) \
+ if (usbh_data.dev_drivers[i]->info->what != -1\
+ && device_info->what != usbh_data.dev_drivers[i]->info->what) {\
+ i++;\
+ continue;\
+ }
+
+
+ int i = 0;
+
+ while (usbh_data.dev_drivers[i]) {
+
+ CHECK_PARTIAL_COMPATIBILITY(ifaceClass);
+ CHECK_PARTIAL_COMPATIBILITY(ifaceSubClass);
+ CHECK_PARTIAL_COMPATIBILITY(ifaceProtocol);
+ CHECK_PARTIAL_COMPATIBILITY(deviceClass);
+ CHECK_PARTIAL_COMPATIBILITY(deviceSubClass);
+ CHECK_PARTIAL_COMPATIBILITY(deviceProtocol);
+ CHECK_PARTIAL_COMPATIBILITY(idVendor);
+ CHECK_PARTIAL_COMPATIBILITY(idProduct);
+
+ return usbh_data.dev_drivers[i];
+ }
+ return 0;
+#undef CHECK_PARTIAL_COMPATIBILITY
+}
+
+
+static void device_register(void *descriptors, uint16_t descriptors_len, usbh_device_t *dev)
+{
+ uint32_t i = 0;
+ dev->drv = 0;
+ uint8_t *buf = (uint8_t *)descriptors;
+
+ dev->drv = 0;
+ dev->drvdata = 0;
+
+ uint8_t desc_len = buf[i];
+ uint8_t desc_type = buf[i + 1];
+
+ usbh_dev_driver_info_t device_info;
+ if (desc_type == USB_DT_DEVICE) {
+ struct usb_device_descriptor *device_desc = (void*)&buf[i];
+ LOG_PRINTF("DEVICE DESCRIPTOR");
+ device_info.deviceClass = device_desc->bDeviceClass;
+ device_info.deviceSubClass = device_desc->bDeviceSubClass;
+ device_info.deviceProtocol = device_desc->bDeviceProtocol;
+ device_info.idVendor = device_desc->idVendor;
+ device_info.idProduct = device_desc->idProduct;
+ } else {
+ LOG_PRINTF("INVALID descriptors pointer - fatal error");
+ return;
+ }
+
+
+ while (i < descriptors_len) {
+ desc_len = buf[i];
+ desc_type = buf[i + 1];
+ switch (desc_type) {
+ case USB_DT_INTERFACE:
+ {
+ LOG_PRINTF("INTERFACE_DESCRIPTOR\n");
+ struct usb_interface_descriptor *iface = (void*)&buf[i];
+ device_info.ifaceClass = iface->bInterfaceClass;
+ device_info.ifaceSubClass = iface->bInterfaceSubClass;
+ device_info.ifaceProtocol = iface->bInterfaceProtocol;
+ const usbh_dev_driver_t *driver = find_driver(&device_info);
+ if (driver) {
+ dev->drv = driver;
+ dev->drvdata = dev->drv->init(dev);
+ if (!dev->drvdata) {
+ LOG_PRINTF("CANT TOUCH THIS");
+ }
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (desc_len == 0) {
+ LOG_PRINTF("PROBLEM WITH PARSE %d\n",i);
+ return;
+ }
+ i += desc_len;
+
+ }
+
+ if (dev->drv && dev->drvdata) {
+ // analyze descriptors
+ LOG_PRINTF("ANALYZE");
+ i = 0;
+ while (i < descriptors_len) {
+ desc_len = buf[i];
+ void *drvdata = dev->drvdata;
+ LOG_PRINTF("[%d]",buf[i+1]);
+ if (dev->drv->analyze_descriptor(drvdata, &buf[i])) {
+ LOG_PRINTF("Device Initialized\n");
+ return;
+ }
+ i += desc_len;
+ }
+ }
+ LOG_PRINTF("Device NOT Initialized\n");
+}
+
+void usbh_init(const void *drivers_lld[], const usbh_dev_driver_t * const device_drivers[])
+{
+ if (!drivers_lld) {
+ return;
+ }
+
+ usbh_data.lld_drivers = (const usbh_driver_t **)drivers_lld;
+ usbh_data.dev_drivers = device_drivers;
+
+ // TODO: init structures
+ uint32_t k = 0;
+ while (usbh_data.lld_drivers[k]) {
+ LOG_PRINTF("DRIVER %d\n", k);
+
+ usbh_device_t * usbh_device =
+ ((usbh_generic_data_t *)(usbh_data.lld_drivers[k])->driver_data)->usbh_device;
+ uint32_t i;
+ for (i = 0; i < USBH_MAX_DEVICES; i++) {
+ usbh_device[i].address = -1;
+ usbh_device[i].drv = 0;
+ usbh_device[i].drvdata = 0;
+ }
+ LOG_PRINTF("DRIVER %d", k);
+ usbh_data.lld_drivers[k]->init(usbh_data.lld_drivers[k]->driver_data);
+
+ k++;
+ }
+}
+
+void device_xfer_control_write(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
+{
+ usbh_packet_t packet;
+
+ packet.data = data;
+ packet.datalen = datalen;
+ packet.address = dev->address;
+ packet.endpoint_address = 0;
+ packet.endpoint_size_max = dev->packet_size_max0;
+ packet.endpoint_type = USBH_EPTYP_CONTROL;
+ packet.speed = dev->speed;
+ packet.callback = callback;
+ packet.callback_arg = dev;
+ packet.toggle = &dev->toggle0;
+
+ usbh_write(dev, &packet);
+ LOG_PRINTF("WR@device...%d | \n", dev->address);
+}
+
+void device_xfer_control_read(void *data, uint16_t datalen, usbh_packet_callback_t callback, usbh_device_t *dev)
+{
+ usbh_packet_t packet;
+
+ packet.data = data;
+ packet.datalen = datalen;
+ packet.address = dev->address;
+ packet.endpoint_address = 0;
+ packet.endpoint_size_max = dev->packet_size_max0;
+ packet.endpoint_type = USBH_EPTYP_CONTROL;
+ packet.speed = dev->speed;
+ packet.callback = callback;
+ packet.callback_arg = dev;
+ packet.toggle = &dev->toggle0;
+
+ usbh_read(dev, &packet);
+ LOG_PRINTF("RD@device...%d | \n", dev->address);
+}
+
+bool usbh_enum_available(void)
+{
+ return !enumeration();
+}
+
+usbh_device_t *usbh_get_free_device(const usbh_device_t *dev)
+{
+ const usbh_driver_t *lld = dev->lld;
+ usbh_generic_data_t *lld_data = lld->driver_data;
+ usbh_device_t *usbh_device = lld_data->usbh_device;
+
+ uint8_t i;
+ LOG_PRINTF("DEV ADDRESS%d\n", dev->address);
+ for (i = 0; i < USBH_MAX_DEVICES; i++) {
+ if (usbh_device[i].address < 0) {
+ LOG_PRINTF("\t\t\t\t\tFOUND: %d", i);
+ usbh_device[i].address = i+1;
+ return &usbh_device[i];
+ } else {
+ LOG_PRINTF("address: %d\n\n\n", usbh_device[i].address);
+ }
+ }
+
+ return 0;
+}
+
+static void device_enumeration_terminate(usbh_device_t *dev)
+{
+ reset_enumeration();
+ dev->state = 0;
+ dev->address = -1;
+}
+
+static void device_enumerate(usbh_device_t *dev, usbh_packet_callback_data_t cb_data)
+{
+ const usbh_driver_t *lld = dev->lld;
+ usbh_generic_data_t *lld_data = lld->driver_data;
+ uint8_t *usbh_buffer = lld_data->usbh_buffer;
+ uint8_t state_start = dev->state; // Detection of hang
+// LOG_PRINTF("\nSTATE: %d\n", state);
+ switch (dev->state) {
+ case 1:
+ {
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ dev->state++;
+ LOG_PRINTF("::%d::", dev->address);
+ device_xfer_control_read(0, 0, device_enumerate, dev);
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ device_enumeration_terminate(dev);
+ ERROR(cb_data.status);
+ break;
+ }
+ }
+ break;
+
+ case 2:
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ if (dev->address == 0) {
+ dev->address = usbh_data.address_temporary;
+ LOG_PRINTF("ADDR: %d\n", dev->address);
+ }
+
+ struct usb_setup_data setup_data;
+
+ setup_data.bmRequestType = 0b10000000;
+ setup_data.bRequest = USB_REQ_GET_DESCRIPTOR;
+ setup_data.wValue = USB_DT_DEVICE << 8;
+ setup_data.wIndex = 0;
+ setup_data.wLength = USB_DT_DEVICE_SIZE;
+
+ dev->state++;
+ device_xfer_control_write(&setup_data, sizeof(setup_data),
+ device_enumerate, dev);
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ device_enumeration_terminate(dev);
+ ERROR(cb_data.status);
+ break;
+ }
+ break;
+
+ case 3:
+ {
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ dev->state++;
+ device_xfer_control_read(&usbh_buffer[0], USB_DT_DEVICE_SIZE,
+ device_enumerate, dev);
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ dev->state = 2;
+
+ // WARNING: Recursion
+ // .. but should work
+ cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK;
+ device_enumerate(dev, cb_data);
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ device_enumeration_terminate(dev);
+ ERROR(cb_data.status);
+ break;
+ }
+ }
+ break;
+
+ case 4:
+ {
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ {
+ struct usb_device_descriptor *ddt =
+ (struct usb_device_descriptor *)&usbh_buffer[0];
+ dev->packet_size_max0 = ddt->bMaxPacketSize0;
+ struct usb_setup_data setup_data;
+
+ setup_data.bmRequestType = 0b10000000;
+ setup_data.bRequest = USB_REQ_GET_DESCRIPTOR;
+ setup_data.wValue = USB_DT_CONFIGURATION << 8;
+ setup_data.wIndex = 0;
+ setup_data.wLength = ddt->bMaxPacketSize0;//USB_DT_CONFIGURATION_SIZE;
+
+ dev->state++;
+ device_xfer_control_write(&setup_data, sizeof(setup_data),
+ device_enumerate, dev);
+ }
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ if (cb_data.transferred_length >= 8) {
+ struct usb_device_descriptor *ddt =
+ (struct usb_device_descriptor *)&usbh_buffer[0];
+ dev->packet_size_max0 = ddt->bMaxPacketSize0;
+ dev->state = 2;
+
+ // WARNING: Recursion
+ // .. but should work
+ cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK;
+ device_enumerate(dev, cb_data);
+ }
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ device_enumeration_terminate(dev);
+ ERROR(cb_data.status);
+ break;
+ }
+ }
+ break;
+
+ case 5:
+ {
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ dev->state++;
+ device_xfer_control_read(&usbh_buffer[USB_DT_DEVICE_SIZE],
+ dev->packet_size_max0, device_enumerate, dev);
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ device_enumeration_terminate(dev);
+ ERROR(cb_data.status);
+ break;
+ }
+ }
+ break;
+
+ case 6:
+ {
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ {
+ struct usb_config_descriptor *cdt =
+ (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE];
+ struct usb_setup_data setup_data;
+ LOG_PRINTF("WRITE: LEN: %d", cdt->wTotalLength);
+ setup_data.bmRequestType = 0b10000000;
+ setup_data.bRequest = USB_REQ_GET_DESCRIPTOR;
+ setup_data.wValue = USB_DT_CONFIGURATION << 8;
+ setup_data.wIndex = 0;
+ setup_data.wLength = cdt->wTotalLength;
+
+ dev->state++;
+ device_xfer_control_write(&setup_data, sizeof(setup_data),
+ device_enumerate, dev);
+ }
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ if (cb_data.transferred_length >= USB_DT_CONFIGURATION_SIZE) {
+ struct usb_config_descriptor *cdt =
+ (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE];
+ if (cb_data.transferred_length <= cdt->wTotalLength) {
+ dev->state = 8;
+
+ // WARNING: Recursion
+ // .. but should work
+ cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK;
+ device_enumerate(dev, cb_data);
+ }
+ }
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ device_enumeration_terminate(dev);
+ ERROR(cb_data.status);
+ break;
+ }
+ }
+ break;
+
+ case 7:
+ {
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ {
+ struct usb_config_descriptor *cdt =
+ (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE];
+ dev->state++;
+ device_xfer_control_read(&usbh_buffer[USB_DT_DEVICE_SIZE],
+ cdt->wTotalLength, device_enumerate, dev);
+ }
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ device_enumeration_terminate(dev);
+ ERROR(cb_data.status);
+ break;
+ }
+ }
+ break;
+
+ case 8:
+ {
+ switch (cb_data.status) {
+ case USBH_PACKET_CALLBACK_STATUS_OK:
+ {
+ struct usb_config_descriptor *cdt =
+ (struct usb_config_descriptor *)&usbh_buffer[USB_DT_DEVICE_SIZE];
+ LOG_PRINTF("TOTAL_LENGTH: %d\n", cdt->wTotalLength);
+ device_register(usbh_buffer, cdt->wTotalLength + USB_DT_DEVICE_SIZE, dev);
+ dev->state++;
+
+ reset_enumeration();
+ }
+ break;
+
+ case USBH_PACKET_CALLBACK_STATUS_EFATAL:
+ case USBH_PACKET_CALLBACK_STATUS_EAGAIN:
+ case USBH_PACKET_CALLBACK_STATUS_ERRSIZ:
+ device_enumeration_terminate(dev);
+ ERROR(cb_data.status);
+ break;
+ }
+
+ }
+ break;
+
+ default:
+ LOG_PRINTF("Error: Unknown state "__FILE__"/%d\n", __LINE__);
+ break;
+ }
+
+ if (state_start == dev->state) {
+ LOG_PRINTF("\n !HANG %d\n", state_start);
+ }
+}
+
+void device_enumeration_start(usbh_device_t *dev)
+{
+ set_enumeration();
+ dev->state = 1;
+
+ // save address
+ uint8_t address = dev->address;
+ dev->address = 0;
+
+ if (dev->speed == USBH_SPEED_LOW) {
+ dev->packet_size_max0 = 8;
+ } else {
+ dev->packet_size_max0 = 64;
+ }
+
+ usbh_data.address_temporary = address;
+
+ LOG_PRINTF("\n\n\n ENUMERATION OF DEVICE@%d STARTED \n\n", address);
+
+ struct usb_setup_data setup_data;
+
+ setup_data.bmRequestType = 0b00000000;
+ setup_data.bRequest = USB_REQ_SET_ADDRESS;
+ setup_data.wValue = address;
+ setup_data.wIndex = 0;
+ setup_data.wLength = 0;
+
+ device_xfer_control_write(&setup_data, sizeof(setup_data),
+ device_enumerate, dev);
+}
+
+void usbh_poll(uint32_t time_curr_us)
+{
+ uint32_t k = 0;
+ while (usbh_data.lld_drivers[k]) {
+ usbh_device_t * usbh_device =
+ ((usbh_generic_data_t *)(usbh_data.lld_drivers[k]->driver_data))->usbh_device;
+ usbh_generic_data_t *lld_data = usbh_data.lld_drivers[k]->driver_data;
+
+ enum USBH_POLL_STATUS poll_status = usbh_data.lld_drivers[k]->poll(lld_data, time_curr_us);
+
+ switch (poll_status) {
+ case USBH_POLL_STATUS_DEVICE_CONNECTED:
+ // New device found
+ LOG_PRINTF("\nDEVICE FOUND\n");
+ usbh_device[0].lld = usbh_data.lld_drivers[k];
+ usbh_device[0].speed = usbh_data.lld_drivers[k]->root_speed(lld_data);
+ usbh_device[0].address = 1;
+
+ device_enumeration_start(&usbh_device[0]);
+ break;
+
+ case USBH_POLL_STATUS_DEVICE_DISCONNECTED:
+ {
+ // Device disconnected
+ if (usbh_device[0].drv && usbh_device[0].drvdata) {
+ usbh_device[0].drv->remove(usbh_device[0].drvdata);
+ }
+ usbh_device[0].drv = 0;
+ usbh_device[0].drvdata = 0;
+
+ uint32_t i;
+ for (i = 1; i < USBH_MAX_DEVICES; i++) {
+ usbh_device[i].address = -1;
+ usbh_device[i].drv = 0;
+ usbh_device[i].drvdata = 0;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (lld_data->usbh_device[0].drv && usbh_device[0].drvdata) {
+ usbh_device[0].drv->poll(usbh_device[0].drvdata, time_curr_us);
+ }
+
+ k++;
+ }
+}
+
+void usbh_read(usbh_device_t *dev, usbh_packet_t *packet)
+{
+ const usbh_driver_t *lld = dev->lld;
+ lld->read(lld->driver_data, packet);
+}
+
+void usbh_write(usbh_device_t *dev, const usbh_packet_t *packet)
+{
+ const usbh_driver_t *lld = dev->lld;
+ lld->write(lld->driver_data, packet);
+}
+
diff --git a/emb/pastilda/lib/libusbhost/usbh_hubbed.h b/emb/pastilda/lib/libusbhost/usbh_hubbed.h
new file mode 100644
index 0000000..6eed1f6
--- /dev/null
+++ b/emb/pastilda/lib/libusbhost/usbh_hubbed.h
@@ -0,0 +1,79 @@
+/*
+ * This file is part of the libusbhost library
+ * hosted at http://github.com/libusbhost/libusbhost
+ *
+ * Copyright (C) 2015 Amir Hammad <amir.hammad@hotmail.com>
+ *
+ *
+ * libusbhost is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef USBH_HUBBED_
+#define USBH_HUBBED_
+
+#include "usbh_config.h"
+
+#include <stdint.h>
+#include <stdbool.h>
+
+/* This must be placed around external function declaration for C++
+ * support. */
+#ifdef __cplusplus
+# define BEGIN_DECLS extern "C" {
+# define END_DECLS }
+#else
+# define BEGIN_DECLS
+# define END_DECLS
+#endif
+
+BEGIN_DECLS
+
+// set to -1 to unused items
+struct _usbh_dev_driver_info {
+ int32_t deviceClass;
+ int32_t deviceSubClass;
+ int32_t deviceProtocol;
+ int32_t idVendor;
+ int32_t idProduct;
+ int32_t ifaceClass;
+ int32_t ifaceSubClass;
+ int32_t ifaceProtocol;
+};
+typedef struct _usbh_dev_driver_info usbh_dev_driver_info_t;
+
+struct _usbh_dev_driver {
+ void *(*init)(void *usbh_dev);
+ bool (*analyze_descriptor)(void *drv, void *descriptor);
+ void (*poll)(void *drvdata, uint32_t time_curr_us);
+ void (*remove)(void *drvdata);
+ const usbh_dev_driver_info_t * const info;
+};
+typedef struct _usbh_dev_driver usbh_dev_driver_t;
+
+void usbh_init(const void *drivers[], const usbh_dev_driver_t * const device_drivers[]);
+
+/**
+ * \brief usbh_poll
+ * \param time_curr_us - use monotically rising time
+ *
+ * time_curr_us:
+ * * can overflow, in time of this writing, after 1s)
+ * * unit is microseconds
+ */
+void usbh_poll(uint32_t time_curr_us);
+
+END_DECLS
+
+#endif
diff --git a/emb/pastilda/lib/libusbhost/usbh_lld_stm32f4.c b/emb/pastilda/lib/libusbhost/usbh_lld_stm32f4.c
new file mode 100644
index 0000000..606f059
--- /dev/null
+++ b/emb/pastilda/lib/libusbhost/usbh_lld_stm32f4.c
@@ -0,0 +1,1059 @@
+/*
+ * This file is part of the libusbhost library
+ * hosted at http://github.com/libusbhost/libusbhost
+ *
+ * Copyright (C) 2015 Amir Hammad <amir.hammad@hotmail.com>
+ *
+ *
+ * libusbhost is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include "driver/usbh_device_driver.h"
+#include "usbh_lld_stm32f4.h"
+#include "usart_helpers.h"
+
+#include <string.h>
+#include <stdint.h>
+#include <libopencm3/stm32/otg_hs.h>
+#include <libopencm3/stm32/otg_fs.h>
+
+/* Receive FIFO size in 32-bit words. */
+#define RX_FIFO_SIZE (64)
+/* Transmit NON-periodic FIFO size in 32-bit words. */
+#define TX_NP_FIFO_SIZE (64)
+/* Transmit periodic FIFO size in 32-bit words. */
+#define TX_P_FIFO_SIZE (64)
+
+enum CHANNEL_STATE {
+ CHANNEL_STATE_FREE = 0,
+ CHANNEL_STATE_WORK = 1
+};
+
+struct _channel {
+ enum CHANNEL_STATE state;
+ usbh_packet_t packet;
+ uint32_t data_index; //used in receive function
+ uint8_t error_count;
+};
+typedef struct _channel channel_t;
+
+enum DEVICE_STATE {
+ DEVICE_STATE_INIT = 0,
+ DEVICE_STATE_RUN = 1,
+ DEVICE_STATE_RESET = 2
+};
+
+enum DEVICE_POLL_STATE {
+ DEVICE_POLL_STATE_DISCONN = 0,
+ DEVICE_POLL_STATE_DEVCONN = 1,
+ DEVICE_POLL_STATE_DEVRST = 2,
+ DEVICE_POLL_STATE_RUN = 3
+};
+
+struct _usbh_lld_stm32f4_driver_data {
+ usbh_generic_data_t generic;
+ const uint32_t base;
+ channel_t *channels;
+ const uint8_t num_channels;
+
+ uint32_t poll_sequence;
+ enum DEVICE_POLL_STATE dpstate;
+ enum DEVICE_STATE state;
+ uint32_t state_prev;//for reset only
+ uint32_t time_curr_us;
+ uint32_t timestamp_us;
+};
+typedef struct _usbh_lld_stm32f4_driver_data usbh_lld_stm32f4_driver_data_t;
+
+
+
+/*
+ * Define correct REBASE. If only one driver is enabled use directly OTG base
+ *
+ */
+#if defined(USE_STM32F4_USBH_DRIVER_FS) || \
+ defined(USE_STM32F4_USBH_DRIVER_HS)
+
+#if defined(USE_STM32F4_USBH_DRIVER_FS) && \
+ defined(USE_STM32F4_USBH_DRIVER_HS)
+#define REBASE(reg) MMIO32(dev->base + reg)
+#define REBASE_CH(reg, x) MMIO32(dev->base + reg(x))
+#elif defined(USE_STM32F4_USBH_DRIVER_FS)
+#define REBASE(reg) MMIO32(USB_OTG_FS_BASE + reg)
+#define REBASE_CH(reg, x) MMIO32(USB_OTG_FS_BASE + reg(x))
+#elif defined(USE_STM32F4_USBH_DRIVER_HS)
+#define REBASE(reg) MMIO32(USB_OTG_HS_BASE + reg)
+#define REBASE_CH(reg, x) MMIO32(USB_OTG_HS_BASE + reg(x))
+#endif
+
+static int8_t get_free_channel(void *drvdata);
+static void channels_init(void *drvdata);
+static void rxflvl_handle(void *drvdata);
+static void free_channel(void *drvdata, uint8_t channel);
+
+
+
+
+
+static inline void reset_start(usbh_lld_stm32f4_driver_data_t *dev)
+{
+
+ // apply reset condition on port
+ REBASE(OTG_HPRT) |= OTG_HPRT_PRST;
+
+ // push current state to stack
+ dev->state_prev = dev->state;
+
+ // move to new state
+ dev->state = DEVICE_STATE_RESET;
+
+ // schedule disable reset condition after ~10ms
+ dev->timestamp_us = dev->time_curr_us;
+}
+
+/**
+ * Should be nonblocking
+ *
+ */
+static void init(void *drvdata)
+{
+ usbh_lld_stm32f4_driver_data_t *dev = drvdata;
+ dev->state = DEVICE_STATE_INIT;
+ dev->poll_sequence = 0;
+ dev->timestamp_us = dev->time_curr_us;
+
+ //Disable interrupts first
+ REBASE(OTG_GAHBCFG) &= ~OTG_GAHBCFG_GINT;
+
+ // Select full speed phy
+ REBASE(OTG_GUSBCFG) |= OTG_GUSBCFG_PHYSEL;
+}
+
+static void stm32f4_usbh_port_channel_setup(
+ void *drvdata, uint32_t channel, uint32_t address,
+ uint32_t eptyp, uint32_t epnum, uint32_t epdir,
+ uint32_t max_packet_size)
+{
+ usbh_lld_stm32f4_driver_data_t *dev = drvdata;
+ channel_t *channels = dev->channels;
+
+ // TODO: maybe to function
+ switch (eptyp) {
+ case USBH_EPTYP_CONTROL:
+ eptyp = OTG_HCCHAR_EPTYP_CONTROL;
+ break;
+ case USBH_EPTYP_BULK:
+ eptyp = OTG_HCCHAR_EPTYP_BULK;
+ break;
+ case USBH_EPTYP_INTERRUPT:
+ // Use bulk transfer also for interrupt, since no difference is on protocol layer
+ // Except different behaviour of the core
+ eptyp = OTG_HCCHAR_EPTYP_BULK;
+ break;
+ case USBH_EPTYP_ISOCHRONOUS:
+ eptyp = OTG_HCCHAR_EPTYP_ISOCHRONOUS;
+ break;
+ default:
+ LOG_PRINTF("\n\n\n\nWRONG EP TYPE\n\n\n\n\n");
+ return;
+ }
+
+ uint32_t speed = 0;
+ if (channels[channel].packet.speed == USBH_SPEED_LOW) {
+ speed = OTG_HCCHAR_LSDEV;
+ }
+
+ REBASE_CH(OTG_HCCHAR, channel) = OTG_HCCHAR_CHENA |
+ (OTG_HCCHAR_DAD_MASK & (address << 22)) |
+ OTG_HCCHAR_MCNT_1 |
+ (OTG_HCCHAR_EPTYP_MASK & (eptyp)) |
+ (speed) |
+ (epdir) |
+ (OTG_HCCHAR_EPNUM_MASK & (epnum << 11)) |
+ (OTG_HCCHAR_MPSIZ_MASK & max_packet_size);
+
+}
+
+
+/**
+ * TODO: Check for maximum datalength
+ */
+static void read(void *drvdata, usbh_packet_t *packet)
+{
+ usbh_lld_stm32f4_driver_data_t *dev = drvdata;
+ channel_t *channels = dev->channels;
+
+ int8_t channel = get_free_channel(dev);
+ if (channel == -1) {
+ // BIG PROBLEM
+ LOG_PRINTF("FATAL ERROR IN, NO CHANNEL LEFT \n");
+ usbh_packet_callback_data_t cb_data;
+ cb_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL;
+ cb_data.transferred_length = 0;
+ packet->callback(packet->callback_arg, cb_data);
+ return;
+ }
+
+ channels[channel].data_index = 0;
+ channels[channel].packet = *packet;
+
+ uint32_t dpid;
+ if (packet->toggle[0]) {
+ dpid = OTG_HCTSIZ_DPID_DATA1;
+ } else {
+ dpid = OTG_HCTSIZ_DPID_DATA0;
+ }
+
+ uint32_t num_packets;
+ if (packet->datalen) {
+ num_packets = ((packet->datalen - 1) / packet->endpoint_size_max) + 1;
+ } else {
+ num_packets = 0;
+ }
+
+ REBASE_CH(OTG_HCTSIZ, channel) = dpid | (num_packets << 19) | packet->datalen;
+
+ stm32f4_usbh_port_channel_setup(dev, channel,
+ packet->address,
+ packet->endpoint_type,
+ packet->endpoint_address,
+ OTG_HCCHAR_EPDIR_IN,
+ packet->endpoint_size_max);
+}
+
+/**
+ *
+ * Bug: datalen > max_packet_size ...
+ */
+static void write(void *drvdata, const usbh_packet_t *packet)
+{
+ usbh_lld_stm32f4_driver_data_t *dev = drvdata;
+ channel_t *channels = dev->channels;
+
+ int8_t channel = get_free_channel(dev);
+
+ if (channel == -1) {
+ // BIG PROBLEM
+ LOG_PRINTF("FATAL ERROR OUT, NO CHANNEL LEFT \n");
+ usbh_packet_callback_data_t cb_data;
+ cb_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL;
+ cb_data.transferred_length = 0;
+ packet->callback(packet->callback_arg, cb_data);
+ return;
+ }
+
+ channels[channel].data_index = 0;
+ channels[channel].packet = *packet;
+
+ uint32_t dpid;
+ if (packet->endpoint_type == USBH_EPTYP_CONTROL) {
+ dpid = OTG_HCTSIZ_DPID_MDATA;
+ packet->toggle[0] = 0;
+ } else if(packet->endpoint_type == USBH_EPTYP_INTERRUPT) {
+ if (packet->toggle[0]) {
+ dpid = OTG_HCTSIZ_DPID_DATA1;
+ } else {
+ dpid = OTG_HCTSIZ_DPID_DATA0;
+ }
+ } else if (packet->endpoint_type == USBH_EPTYP_BULK) {
+ if (packet->toggle[0]) {
+ dpid = OTG_HCTSIZ_DPID_DATA1;
+ } else {
+ dpid = OTG_HCTSIZ_DPID_DATA0;
+ }
+ } else {
+ dpid = OTG_HCTSIZ_DPID_DATA0; // ! TODO: BUG
+ LOG_PRINTF("BUG, %d",__LINE__);
+ }
+
+ uint32_t num_packets;
+ if (packet->datalen) {
+ num_packets = ((packet->datalen - 1) / packet->endpoint_size_max) + 1;
+ } else {
+ num_packets = 1;
+ }
+ REBASE_CH(OTG_HCTSIZ, channel) = dpid | (num_packets << 19) | packet->datalen;
+
+ stm32f4_usbh_port_channel_setup(dev, channel,
+ packet->address,
+ packet->endpoint_type,
+ packet->endpoint_address,
+ OTG_HCCHAR_EPDIR_OUT,
+ packet->endpoint_size_max);
+
+ if (packet->endpoint_type == USBH_EPTYP_CONTROL ||
+ packet->endpoint_type == USBH_EPTYP_BULK) {
+
+ volatile uint32_t *fifo = &REBASE_CH(OTG_FIFO, channel) + RX_FIFO_SIZE;
+ const uint32_t * buf32 = packet->data;
+ int i;
+ LOG_PRINTF("\nSending[%d]: ", packet->datalen);
+ for(i = packet->datalen; i >= 4; i-=4) {
+ const uint8_t *buf8 = (const uint8_t *)buf32;
+ LOG_PRINTF("%02X %02X %02X %02X, ", buf8[0], buf8[1], buf8[2], buf8[3]);
+ *fifo++ = *buf32++;
+
+ }
+
+ if (i > 0) {
+ *fifo = *buf32&((1 << (8*i)) - 1);
+ uint8_t *buf8 = (uint8_t *)buf32;
+ while (i--) {
+ LOG_PRINTF("%02X ", *buf8++);
+ }
+ }
+ LOG_PRINTF("\n");
+
+ } else {
+ volatile uint32_t *fifo = &REBASE_CH(OTG_FIFO, channel) +
+ RX_FIFO_SIZE + TX_NP_FIFO_SIZE;
+ const uint32_t * buf32 = packet->data;
+ int i;
+ for(i = packet->datalen; i > 0; i-=4) {
+ *fifo++ = *buf32++;
+ }
+ }
+ LOG_PRINTF("->WRITE %08X\n", REBASE_CH(OTG_HCCHAR, channel));
+}
+
+static void rxflvl_handle(void *drvdata)
+{
+ usbh_lld_stm32f4_driver_data_t *dev = drvdata;
+ channel_t *channels = dev->channels;
+ uint32_t rxstsp = REBASE(OTG_GRXSTSP);
+ uint8_t channel = rxstsp&0xf;
+ uint32_t len = (rxstsp>>4) & 0x1ff;
+ if ((rxstsp&OTG_GRXSTSP_PKTSTS_MASK) == OTG_GRXSTSP_PKTSTS_IN) {
+ uint8_t *data = channels[channel].packet.data;
+ uint32_t *buf32 = (uint32_t *)&data[channels[channel].data_index];
+
+ int32_t i;
+ uint32_t extra;
+ if (!len) {
+ return;
+ }
+ // Receive data from fifo
+ volatile uint32_t *fifo = &REBASE_CH(OTG_FIFO, channel);
+ for (i = len; i > 4; i -= 4) {
+ *buf32++ = *fifo++;
+ }
+ extra = *fifo;
+
+ memcpy(buf32, &extra, i);
+ channels[channel].data_index += len;
+
+ // If transfer not complete, Enable channel to continue
+ if ( channels[channel].data_index < channels[channel].packet.datalen) {
+ if (len == channels[channel].packet.endpoint_size_max) {
+ REBASE_CH(OTG_HCCHAR, channel) |= OTG_HCCHAR_CHENA;
+ LOG_PRINTF("CHENA[%d/%d] ", channels[channel].data_index, channels[channel].packet.datalen);
+ }
+
+ }
+
+ } else if ((rxstsp&OTG_GRXSTSP_PKTSTS_MASK) == OTG_GRXSTSP_PKTSTS_IN_COMP) {
+#ifdef USART_DEBUG
+ uint32_t i;
+ LOG_PRINTF("\nDATA: ");
+ for (i = 0; i < channels[channel].data_index; i++) {
+ uint8_t *data = channels[channel].packet.data;
+ LOG_PRINTF("%02X ", data[i]);
+ }
+#endif
+ } else if ((rxstsp&OTG_GRXSTSP_PKTSTS_MASK) == OTG_GRXSTSP_PKTSTS_CHH) {
+
+ } else {
+
+ }
+}
+
+static enum USBH_POLL_STATUS poll_run(usbh_lld_stm32f4_driver_data_t *dev)
+{
+ uint32_t reg;
+ channel_t *channels = dev->channels;
+
+ if (dev->dpstate == DEVICE_POLL_STATE_DISCONN) {
+ reg = REBASE(OTG_GINTSTS);
+ REBASE(OTG_GINTSTS) = reg;
+ // Check for connection of device
+ if ((REBASE(OTG_HPRT) & OTG_HPRT_PCDET) &&
+ (REBASE(OTG_HPRT) & OTG_HPRT_PCSTS) ) {
+
+ dev->dpstate = DEVICE_POLL_STATE_DEVCONN;
+ dev->timestamp_us = dev->time_curr_us;
+ return USBH_POLL_STATUS_NONE;
+ }
+ }
+
+ if (dev->dpstate == DEVICE_POLL_STATE_DEVCONN) {
+ // May be other condition, e.g. Debounce done,
+ // using 0.5s wait by default
+ if (dev->time_curr_us - dev->timestamp_us < 500000) {
+ return USBH_POLL_STATUS_NONE;
+ }
+
+ if ((REBASE(OTG_HPRT) & OTG_HPRT_PCDET) &&
+ (REBASE(OTG_HPRT) & OTG_HPRT_PCSTS) ) {
+ if ((REBASE(OTG_HPRT) & OTG_HPRT_PSPD_MASK) == OTG_HPRT_PSPD_FULL) {
+ REBASE(OTG_HFIR) = (REBASE(OTG_HFIR) & ~OTG_HFIR_FRIVL_MASK) | 48000;
+ if ((REBASE(OTG_HCFG) & OTG_HCFG_FSLSPCS_MASK) != OTG_HCFG_FSLSPCS_48MHz) {
+ REBASE(OTG_HCFG) = (REBASE(OTG_HCFG) & ~OTG_HCFG_FSLSPCS_MASK) | OTG_HCFG_FSLSPCS_48MHz;
+ LOG_PRINTF("\n Reset Full-Speed \n");
+ }
+ channels_init(dev);
+ dev->dpstate = DEVICE_POLL_STATE_DEVRST;
+ reset_start(dev);
+
+ } else if ((REBASE(OTG_HPRT) & OTG_HPRT_PSPD_MASK) == OTG_HPRT_PSPD_LOW) {
+ REBASE(OTG_HFIR) = (REBASE(OTG_HFIR) & ~OTG_HFIR_FRIVL_MASK) | 6000;
+ if ((REBASE(OTG_HCFG) & OTG_HCFG_FSLSPCS_MASK) != OTG_HCFG_FSLSPCS_6MHz) {
+ REBASE(OTG_HCFG) = (REBASE(OTG_HCFG) & ~OTG_HCFG_FSLSPCS_MASK) | OTG_HCFG_FSLSPCS_6MHz;
+ LOG_PRINTF("\n Reset Low-Speed \n");
+ }
+
+ channels_init(dev);
+ dev->dpstate = DEVICE_POLL_STATE_DEVRST;
+ reset_start(dev);
+ }
+ return USBH_POLL_STATUS_NONE;
+ }
+ }
+
+ if (dev->dpstate == DEVICE_POLL_STATE_DEVRST) {
+ if (dev->time_curr_us - dev->timestamp_us < 210000) {
+ return USBH_POLL_STATUS_NONE;
+ } else {
+ dev->dpstate = DEVICE_POLL_STATE_RUN;
+ }
+ }
+
+ // ELSE RUN
+
+ if (REBASE(OTG_GINTSTS) & OTG_GINTSTS_SOF) {
+ REBASE(OTG_GINTSTS) = OTG_GINTSTS_SOF;
+ }
+
+ while (REBASE(OTG_GINTSTS) & OTG_GINTSTS_RXFLVL) {
+ //receive data
+ rxflvl_handle(dev);
+ }
+
+ if (REBASE(OTG_GINTSTS) & OTG_GINTSTS_HPRTINT) {
+ if (REBASE(OTG_HPRT) & OTG_HPRT_PENCHNG) {
+ uint32_t hprt = REBASE(OTG_HPRT);
+ // Clear Interrupt
+ // HARDWARE BUG - not mentioned in errata
+ // To clear interrupt write 0 to PENA
+ // To disable port write 1 to PENCHNG
+ REBASE(OTG_HPRT) &= ~OTG_HPRT_PENA;
+ LOG_PRINTF("PENCHNG");
+ if ((hprt & OTG_HPRT_PENA)) {
+ return USBH_POLL_STATUS_DEVICE_CONNECTED;
+ }
+
+ }
+
+ if (REBASE(OTG_HPRT) & OTG_HPRT_POCCHNG) {
+ // TODO: Check for functionality
+ REBASE(OTG_HPRT) |= OTG_HPRT_POCCHNG;
+ LOG_PRINTF("POCCHNG");
+ }
+ }
+
+ if (REBASE(OTG_GINTSTS) & OTG_GINTSTS_DISCINT) {
+ REBASE(OTG_GINTSTS) = OTG_GINTSTS_DISCINT;
+ LOG_PRINTF("DISCINT");
+
+ /*
+ * When the voltage drops, DISCINT interrupt is generated although
+ * Device is connected, so there is no need to reinitialize channels.
+ * Often, DISCINT is bad interpreted upon insertion of device
+ */
+ if (!(REBASE(OTG_HPRT) & OTG_HPRT_PCSTS)) {
+ LOG_PRINTF("discint processsing...");
+ channels_init(dev);
+ }
+ reg = REBASE(OTG_GINTSTS);
+ REBASE(OTG_GINTSTS) = reg;
+ dev->dpstate = DEVICE_POLL_STATE_DISCONN;
+ return USBH_POLL_STATUS_DEVICE_DISCONNECTED;
+ }
+
+ if (REBASE(OTG_GINTSTS) & OTG_GINTSTS_HCINT) {
+ uint32_t channel;
+
+ for(channel = 0; channel < dev->num_channels; channel++)
+ {
+ if (channels[channel].state != CHANNEL_STATE_WORK ||
+ !(REBASE(OTG_HAINT)&(1<<channel))) {
+ continue;
+ }
+ uint32_t hcint = REBASE_CH(OTG_HCINT, channel);
+ uint8_t eptyp = channels[channel].packet.endpoint_type;
+
+ // Write
+ if (!(REBASE_CH(OTG_HCCHAR, channel)&OTG_HCCHAR_EPDIR_IN)) {
+
+ if (hcint & OTG_HCINT_NAK) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_NAK;
+ LOG_PRINTF("NAK");
+
+ REBASE_CH(OTG_HCCHAR, channel) |= OTG_HCCHAR_CHENA;
+
+ }
+
+ if (hcint & OTG_HCINT_ACK) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_ACK;
+ LOG_PRINTF("ACK");
+ if (eptyp == USBH_EPTYP_CONTROL) {
+ channels[channel].packet.toggle[0] = 1;
+ } else {
+ channels[channel].packet.toggle[0] ^= 1;
+ }
+ }
+
+ if (hcint & OTG_HCINT_XFRC) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_XFRC;
+ LOG_PRINTF("XFRC");
+
+ free_channel(dev, channel);
+
+ usbh_packet_callback_data_t cb_data;
+ cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK;
+ cb_data.transferred_length = channels[channel].data_index;
+
+ channels[channel].packet.callback(
+ channels[channel].packet.callback_arg,
+ cb_data);
+ continue;
+ }
+
+ if (hcint & OTG_HCINT_FRMOR) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_FRMOR;
+ LOG_PRINTF("FRMOR");
+
+ usbh_packet_callback_data_t cb_data;
+ cb_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL;
+ cb_data.transferred_length = 0;
+
+ channels[channel].packet.callback(
+ channels[channel].packet.callback_arg,
+ cb_data);
+ free_channel(dev, channel);
+ }
+
+ if (hcint & OTG_HCINT_TXERR) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_TXERR;
+ LOG_PRINTF("TXERR");
+
+ free_channel(dev, channel);
+
+ usbh_packet_callback_data_t cb_data;
+ cb_data.status = USBH_PACKET_CALLBACK_STATUS_EAGAIN;
+ cb_data.transferred_length = 0;
+
+ channels[channel].packet.callback(
+ channels[channel].packet.callback_arg,
+ cb_data);
+
+
+ }
+
+ if (hcint & OTG_HCINT_STALL) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_STALL;
+ LOG_PRINTF("STALL");
+
+ free_channel(dev, channel);
+
+ usbh_packet_callback_data_t cb_data;
+ cb_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL;
+ cb_data.transferred_length = 0;
+
+
+ channels[channel].packet.callback(
+ channels[channel].packet.callback_arg,
+ cb_data);
+ }
+
+ if (hcint & OTG_HCINT_CHH) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_CHH;
+ LOG_PRINTF("CHH");
+
+ free_channel(dev, channel);
+ }
+ } else { // Read
+
+ if (hcint & OTG_HCINT_NAK) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_NAK;
+ if (eptyp == USBH_EPTYP_CONTROL) {
+ LOG_PRINTF("NAK");
+ }
+
+ REBASE_CH(OTG_HCCHAR, channel) |= OTG_HCCHAR_CHENA;
+
+ }
+
+ if (hcint & OTG_HCINT_DTERR) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_DTERR;
+ LOG_PRINTF("DTERR");
+ }
+
+ if (hcint & OTG_HCINT_ACK) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_ACK;
+ LOG_PRINTF("ACK");
+
+ channels[channel].packet.toggle[0] ^= 1;
+
+ }
+
+
+
+ if (hcint & OTG_HCINT_XFRC) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_XFRC;
+ LOG_PRINTF("XFRC");
+
+ free_channel(dev, channel);
+ usbh_packet_callback_data_t cb_data;
+ if (channels[channel].data_index == channels[channel].packet.datalen) {
+ cb_data.status = USBH_PACKET_CALLBACK_STATUS_OK;
+ } else {
+ cb_data.status = USBH_PACKET_CALLBACK_STATUS_ERRSIZ;
+ }
+ cb_data.transferred_length = channels[channel].data_index;
+
+ channels[channel].packet.callback(
+ channels[channel].packet.callback_arg,
+ cb_data);
+
+ continue;
+ }
+
+ if (hcint & OTG_HCINT_BBERR) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_BBERR;
+ LOG_PRINTF("BBERR");
+ free_channel(dev, channel);
+
+ usbh_packet_callback_data_t cb_data;
+ cb_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL;
+ cb_data.transferred_length = 0;
+
+ channels[channel].packet.callback(
+ channels[channel].packet.callback_arg,
+ cb_data);
+ }
+
+ if (hcint & OTG_HCINT_FRMOR) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_FRMOR;
+ LOG_PRINTF("FRMOR");
+
+ }
+
+ if (hcint & OTG_HCINT_TXERR) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_TXERR;
+ LOG_PRINTF("TXERR");
+
+ free_channel(dev, channel);
+
+ usbh_packet_callback_data_t cb_data;
+ cb_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL;
+ cb_data.transferred_length = 0;
+
+ channels[channel].packet.callback(
+ channels[channel].packet.callback_arg,
+ cb_data);
+
+ }
+
+ if (hcint & OTG_HCINT_STALL) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_STALL;
+ LOG_PRINTF("STALL");
+
+ free_channel(dev, channel);
+
+ usbh_packet_callback_data_t cb_data;
+ cb_data.status = USBH_PACKET_CALLBACK_STATUS_EFATAL;
+ cb_data.transferred_length = 0;
+
+ channels[channel].packet.callback(
+ channels[channel].packet.callback_arg,
+ cb_data);
+
+ }
+ if (hcint & OTG_HCINT_CHH) {
+ REBASE_CH(OTG_HCINT, channel) = OTG_HCINT_CHH;
+ LOG_PRINTF("CHH");
+ free_channel(dev, channel);
+ }
+
+ }
+ }
+ }
+
+ if (REBASE(OTG_GINTSTS) & OTG_GINTSTS_MMIS) {
+ REBASE(OTG_GINTSTS) = OTG_GINTSTS_MMIS;
+ LOG_PRINTF("Mode mismatch");
+ }
+
+ if (REBASE(OTG_GINTSTS) & OTG_GINTSTS_IPXFR) {
+ REBASE(OTG_GINTSTS) = OTG_GINTSTS_IPXFR;
+ LOG_PRINTF("IPXFR");
+ }
+
+ return USBH_POLL_STATUS_NONE;
+}
+
+/*
+ * Sequence numbers are hardcoded, since it is used
+ * locally in poll_init() function.
+ * If value of poll_sequence is needed elsewhere, enum must be defined.
+ *
+ */
+static void poll_init(usbh_lld_stm32f4_driver_data_t *dev)
+{
+ //=======================================
+
+ int done = 0;
+ /* Wait for AHB idle. */
+ switch (dev->poll_sequence) {
+ case 0:// wait until AHBIDL is set
+ if (REBASE(OTG_GRSTCTL) & OTG_GRSTCTL_AHBIDL) {
+ done = 1;
+ }
+ break;
+
+ case 1:// wait 1ms and issue core soft reset
+
+ // needs delay to not hang?? Do not know why.
+ // Maybe after AHBIDL is set, it needs to set up some things
+ if (dev->time_curr_us - dev->timestamp_us > 1000) {
+ REBASE(OTG_GRSTCTL) |= OTG_GRSTCTL_CSRST;
+ done = 1;
+ }
+ break;
+
+ case 2:// wait until core soft reset processing is done
+ if (!(REBASE(OTG_GRSTCTL) & OTG_GRSTCTL_CSRST)) {
+ done = 1;
+ }
+ break;
+
+ case 3:// wait for 50ms
+ if (dev->time_curr_us - dev->timestamp_us > 50000) {
+ done = 1;
+ }
+ break;
+
+ case 4:// wait until AHBIDL is set and power up the USB
+ if (REBASE(OTG_GRSTCTL) & OTG_GRSTCTL_AHBIDL) {
+ REBASE(OTG_GCCFG) = OTG_GCCFG_VBUSASEN | OTG_GCCFG_VBUSBSEN |
+ OTG_GCCFG_NOVBUSSENS | OTG_GCCFG_PWRDWN;
+ done = 1;
+ }
+ break;
+
+ case 5:// wait for 50ms and force host only mode
+ if (dev->time_curr_us - dev->timestamp_us > 50000) {
+
+ // Core initialized
+ // Force host only mode.
+ REBASE(OTG_GUSBCFG) |= OTG_GUSBCFG_FHMOD;
+ done = 1;
+ }
+ break;
+
+ case 6:// wait for 200ms and reset PHY clock start reset processing
+ if (dev->time_curr_us - dev->timestamp_us > 200000) {
+ /* Restart the PHY clock. */
+ REBASE(OTG_PCGCCTL) = 0;
+
+ REBASE(OTG_HCFG) = (REBASE(OTG_HCFG) & ~OTG_HCFG_FSLSPCS_MASK) |
+ OTG_HCFG_FSLSPCS_48MHz;
+
+ // Start reset processing
+ REBASE(OTG_HPRT) |= OTG_HPRT_PRST;
+
+ done = 1;
+
+ }
+ break;
+
+ case 7:// wait for reset processing to be done(12ms), disable PRST
+ if (dev->time_curr_us - dev->timestamp_us > 12000) {
+
+ REBASE(OTG_HPRT) &= ~OTG_HPRT_PRST;
+ done = 1;
+ }
+ break;
+
+ case 8:// wait 12ms after PRST was disabled, configure fifo
+ if (dev->time_curr_us - dev->timestamp_us > 12000) {
+
+ REBASE(OTG_HCFG) &= ~OTG_HCFG_FSLSS;
+
+ REBASE(OTG_GRXFSIZ) = RX_FIFO_SIZE;
+ REBASE(OTG_GNPTXFSIZ) = (TX_NP_FIFO_SIZE << 16) |
+ RX_FIFO_SIZE;
+ REBASE(OTG_HPTXFSIZ) = (TX_P_FIFO_SIZE << 16) |
+ (RX_FIFO_SIZE + TX_NP_FIFO_SIZE);
+
+ // FLUSH RX FIFO
+ REBASE(OTG_GRSTCTL) |= OTG_GRSTCTL_RXFFLSH;
+
+ done = 1;
+ }
+ break;
+
+ case 9: // wait to RX FIFO become flushed, flush TX
+ if (!(REBASE(OTG_GRSTCTL) & OTG_GRSTCTL_RXFFLSH)) {
+ REBASE(OTG_GRSTCTL) |= OTG_GRSTCTL_TXFFLSH | (0x10 << 6);
+
+ done = 1;
+ }
+ break;
+
+ case 10: // wait to TX FIFO become flushed
+ if (!(REBASE(OTG_GRSTCTL) & OTG_GRSTCTL_TXFFLSH)) {
+
+ channels_init(dev);
+
+ REBASE(OTG_GOTGINT) |= 1 << 19;
+ REBASE(OTG_GINTMSK) = 0;
+ REBASE(OTG_GINTSTS) = ~0;
+ REBASE(OTG_HPRT) |= OTG_HPRT_PPWR;
+
+ done = 1;
+ }
+ break;
+
+ case 11: // wait 200ms
+ if (dev->time_curr_us - dev->timestamp_us > 200000) {
+
+ // Uncomment to enable Interrupt generation
+ REBASE(OTG_GAHBCFG) |= OTG_GAHBCFG_GINT;
+
+ LOG_PRINTF("INIT COMPLETE\n");
+
+ // Finish
+ dev->state = DEVICE_STATE_RUN;
+ dev->dpstate = DEVICE_POLL_STATE_DISCONN;
+
+ done = 1;
+ }
+ }
+
+ if (done) {
+ dev->poll_sequence++;
+ dev->timestamp_us = dev->time_curr_us;
+ LOG_PRINTF("\t\t POLL SEQUENCE %d\n", dev->poll_sequence);
+ }
+
+}
+
+static void poll_reset(usbh_lld_stm32f4_driver_data_t *dev)
+{
+ if (dev->time_curr_us - dev->timestamp_us > 10000) {
+ REBASE(OTG_HPRT) &= ~OTG_HPRT_PRST;
+ dev->state = dev->state_prev;
+ dev->state_prev = DEVICE_STATE_RESET;
+
+ LOG_PRINTF("RESET");
+ } else {
+ LOG_PRINTF("waiting %d < %d\n",dev->time_curr_us, dev->timestamp_us);
+ }
+}
+
+static enum USBH_POLL_STATUS poll(void *drvdata, uint32_t time_curr_us)
+{
+ (void)time_curr_us;
+
+ usbh_lld_stm32f4_driver_data_t *dev = drvdata;
+ enum USBH_POLL_STATUS ret = USBH_POLL_STATUS_NONE;
+
+ dev->time_curr_us = time_curr_us;
+
+ switch (dev->state) {
+ case DEVICE_STATE_RUN:
+ ret = poll_run(dev);
+ //dev->channels[0].packet.data
+ break;
+
+ case DEVICE_STATE_INIT:
+ poll_init(dev);
+ break;
+
+ case DEVICE_STATE_RESET:
+ poll_reset(dev);
+ break;
+
+ default:
+ break;
+ }
+
+ return ret;
+
+}
+
+
+/**
+ *
+ * Returns positive free channel id
+ * otherwise -1 for error
+ */
+static int8_t get_free_channel(void *drvdata)
+{
+ usbh_lld_stm32f4_driver_data_t *dev = drvdata;
+ channel_t *channels = dev->channels;
+ uint32_t i = 0;
+ for (i = 0; i < dev->num_channels; i++) {
+ if (dev->channels[i].state == CHANNEL_STATE_FREE &&
+ !(REBASE_CH(OTG_HCCHAR, i) & OTG_HCCHAR_CHENA)) {
+ channels[i].state = CHANNEL_STATE_WORK;
+ REBASE_CH(OTG_HCINT, i) = ~0;
+ REBASE_CH(OTG_HCINTMSK, i) |= OTG_HCINTMSK_ACKM | OTG_HCINTMSK_NAKM |
+ OTG_HCINTMSK_TXERRM | OTG_HCINTMSK_XFRCM |
+ OTG_HCINTMSK_DTERRM | OTG_HCINTMSK_BBERRM |
+ OTG_HCINTMSK_CHHM | OTG_HCINTMSK_STALLM |
+ OTG_HCINTMSK_FRMORM;
+ REBASE(OTG_HAINTMSK) |= (1 << i);
+ dev->channels[i].error_count = 0;
+ return i;
+ }
+ }
+ return -1;
+}
+
+/*
+ * Do not clear callback and callback data, so channel can be freed even before callback is called
+ * This saves number of active channels: When one transfer ends, in callback driver can write/read to this channel again (indirectly)
+ */
+static void free_channel(void *drvdata, uint8_t channel)
+{
+ usbh_lld_stm32f4_driver_data_t *dev = drvdata;
+ channel_t *channels = dev->channels;
+
+ if (REBASE_CH(OTG_HCCHAR, channel) & OTG_HCCHAR_CHENA) {
+ REBASE_CH(OTG_HCCHAR, channel) |= OTG_HCCHAR_CHDIS;
+ REBASE_CH(OTG_HCINT, channel) = ~0;
+ LOG_PRINTF("\nDisabling channel %d\n", channel);
+ } else {
+ channels[channel].state = CHANNEL_STATE_FREE;
+ }
+}
+/**
+ * Init channels
+ */
+static void channels_init(void *drvdata)
+{
+ usbh_lld_stm32f4_driver_data_t *dev = drvdata;
+
+ uint32_t i = 0;
+ for (i = 0; i < dev->num_channels; i++) {
+ REBASE_CH(OTG_HCINT, i) = ~0;
+ REBASE_CH(OTG_HCINTMSK, i) = 0x7ff;
+ free_channel(dev, i);
+ }
+
+ // Enable interrupt mask bits for all channels
+ REBASE(OTG_HAINTMSK) = (1 << dev->num_channels) - 1;
+}
+
+/**
+ * Get speed of connected device
+ *
+ */
+static uint8_t root_speed(void *drvdata)
+{
+ usbh_lld_stm32f4_driver_data_t *dev = drvdata;
+ (void)dev;
+ uint32_t hprt_speed = REBASE(OTG_HPRT) & OTG_HPRT_PSPD_MASK;
+ if (hprt_speed == OTG_HPRT_PSPD_LOW) {
+ return USBH_SPEED_LOW;
+ } else if(hprt_speed == OTG_HPRT_PSPD_FULL) {
+ return USBH_SPEED_FULL;
+ } else if(hprt_speed == OTG_HPRT_PSPD_HIGH) {
+ return USBH_SPEED_HIGH;
+ } else {
+ // Should not happen(let the compiler be happy)
+ return USBH_SPEED_FULL;
+ }
+}
+#endif // if defined otg_hs or otg_fs
+
+
+#ifdef USART_DEBUG
+
+/**
+ * Just for debug
+ */
+void print_channels(const void *lld)
+{
+ usbh_lld_stm32f4_driver_data_t *dev = ((usbh_driver_t *)lld)->driver_data;
+ channel_t *channels = dev->channels;
+ int32_t i;
+ LOG_PRINTF("\nCHANNELS: \n");
+ for (i = 0;i < dev->num_channels;i++) {
+ LOG_PRINTF("%4d %4d %4d %08X\n", channels[i].state, channels[i].packet.address, channels[i].packet.datalen, MMIO32(dev->base + OTG_HCINT(i)));
+ }
+}
+#endif
+
+// USB Full Speed - OTG_FS
+#if defined(USE_STM32F4_USBH_DRIVER_FS)
+#define NUM_CHANNELS_FS (8)
+static channel_t channels_fs[NUM_CHANNELS_FS];
+static usbh_lld_stm32f4_driver_data_t driver_data_fs = {
+ .base = USB_OTG_FS_BASE,
+ .channels = channels_fs,
+ .num_channels = NUM_CHANNELS_FS
+};
+static const usbh_driver_t driver_fs = {
+ .init = init,
+ .poll = poll,
+ .read = read,
+ .write = write,
+ .root_speed = root_speed,
+ .driver_data = &driver_data_fs
+};
+#endif
+
+// USB High Speed - OTG_HS
+#if defined(USE_STM32F4_USBH_DRIVER_HS)
+#define NUM_CHANNELS_HS (12)
+static channel_t channels_hs[NUM_CHANNELS_HS];
+static usbh_lld_stm32f4_driver_data_t driver_data_hs = {
+ .base = USB_OTG_HS_BASE,
+ .channels = channels_hs,
+ .num_channels = NUM_CHANNELS_HS
+};
+static const usbh_driver_t driver_hs = {
+ .init = init,
+ .poll = poll,
+ .read = read,
+ .write = write,
+ .root_speed = root_speed,
+ .driver_data = &driver_data_hs
+};
+#endif
+
+const void *usbh_lld_stm32f4_drivers[] = {
+#if defined(USE_STM32F4_USBH_DRIVER_FS)
+ &driver_fs,
+#endif
+
+#if defined(USE_STM32F4_USBH_DRIVER_HS)
+ &driver_hs,
+#endif
+ 0
+};
diff --git a/emb/pastilda/lib/libusbhost/usbh_lld_stm32f4.h b/emb/pastilda/lib/libusbhost/usbh_lld_stm32f4.h
new file mode 100644
index 0000000..07f0fb1
--- /dev/null
+++ b/emb/pastilda/lib/libusbhost/usbh_lld_stm32f4.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the libusbhost library
+ * hosted at http://github.com/libusbhost/libusbhost
+ *
+ * Copyright (C) 2015 Amir Hammad <amir.hammad@hotmail.com>
+ *
+ *
+ * libusbhost is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef USBH_LLD_STM32F4_H_
+#define USBH_LLD_STM32F4_H_
+
+#include "usbh_hubbed.h"
+
+#include <stdint.h>
+
+BEGIN_DECLS
+
+// pass this to usbh init
+extern const void *usbh_lld_stm32f4_drivers[];
+
+#ifdef USART_DEBUG
+void print_channels(const void *drvdata);
+#else
+#define print_channels(arg) ((void)arg)
+#endif
+
+END_DECLS
+
+#endif
diff --git a/emb/pastilda/main.cpp b/emb/pastilda/main.cpp
new file mode 100644
index 0000000..3268a72
--- /dev/null
+++ b/emb/pastilda/main.cpp
@@ -0,0 +1,22 @@
+#include "app.h"
+#include "stdio.h"
+using namespace Application;
+
+#ifdef DEBUG
+ #define DEBUG_PRINT(x) printf(x)
+#else
+ #define DEBUG_PRINT(x) do {} while (0)
+#endif
+
+extern "C" void initialise_monitor_handles(void);
+
+int main()
+{
+ //initialise_monitor_handles();
+ App *app = new App();
+ while(1) {
+ app->process();
+ }
+
+ return (0);
+}
diff --git a/emb/pastilda/stm32f407vg.ld b/emb/pastilda/stm32f407vg.ld
new file mode 100644
index 0000000..c5e1bf8
--- /dev/null
+++ b/emb/pastilda/stm32f407vg.ld
@@ -0,0 +1,7 @@
+MEMORY
+{
+ rom (rx) : ORIGIN = 0x08000000, LENGTH = 1M
+ ram (rwx) : ORIGIN = 0x20000000, LENGTH = 128K
+}
+
+INCLUDE libopencm3_stm32f4.ld \ No newline at end of file
diff --git a/lib/libopencm3 b/lib/libopencm3
new file mode 160000
+Subproject 3da3a4d157333f5ff638cfa933531f1a6a49aec