diff options
author | thirdpin <n_lazareva@mail.ru> | 2016-07-13 13:55:27 +0300 |
---|---|---|
committer | thirdpin <n_lazareva@mail.ru> | 2016-07-13 13:55:27 +0300 |
commit | 03fb98cead3b9b3bf07a786581a7e91817dfcd0e (patch) | |
tree | a048a3c7315ea700fd718d130d0f4d7333af8093 | |
parent | b5708bc84aa18c19ed384f3ca52e429a7e66cc23 (diff) |
initial commit
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=""../..\..\lib\libopencm3\include""/> + <listOptionValue builtIn="false" value=""../..\..\lib\libopencm3\lib""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/app}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/hw}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/hw/usb_device}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/hw/usb_host}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/lib/libusbhost}""/> + </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=""../..\..\lib\libopencm3\include""/> + <listOptionValue builtIn="false" value=""../..\..\lib\libopencm3\lib""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/app}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/hw}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/hw/usb_device}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/hw/usb_host}""/> + <listOptionValue builtIn="false" value=""${workspace_loc:/${ProjName}/lib/libusbhost}""/> + </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=""../..\..\lib\libopencm3\lib""/> + </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 "${INPUTS}"" 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 "${INPUTS}"" 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 |