Subversion Repositories FlightCtrl

Compare Revisions

Ignore whitespace Rev 1820 → Rev 1821

/branches/dongfang_FC_rewrite/sendOutData.c
File deleted
/branches/dongfang_FC_rewrite/- Copy (2).cproject
0,0 → 1,778
<?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="0.213957337">
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="0.213957337" moduleId="org.eclipse.cdt.core.settings" name="Default">
<externalSettings/>
<extensions>
<extension id="org.eclipse.cdt.core.VCErrorParser" 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.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/>
</extensions>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<configuration artifactName="${ProjName}" buildProperties="" description="" id="0.213957337" name="Default" parent="org.eclipse.cdt.build.core.prefbase.cfg">
<folderInfo id="0.213957337." name="/" resourcePath="">
<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.1407298090" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain">
<targetPlatform id="org.eclipse.cdt.build.core.prefbase.toolchain.1407298090.387718105" name=""/>
<builder id="org.eclipse.cdt.build.core.settings.default.builder.1420554535" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.libs.546321738" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/>
<tool id="org.eclipse.cdt.build.core.settings.holder.1369884461" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.245563341" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.606246534" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder">
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.234895837" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
<tool id="org.eclipse.cdt.build.core.settings.holder.508232992" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder">
<option id="org.eclipse.cdt.build.core.settings.holder.incpaths.1552334249" name="Include Paths" superClass="org.eclipse.cdt.build.core.settings.holder.incpaths" valueType="includePath">
<listOptionValue builtIn="false" value="&quot;C:\WinAVR-20100110\avr\include&quot;"/>
</option>
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1030732404" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/>
</tool>
</toolChain>
</folderInfo>
<sourceEntries>
<entry excluding="*.d,*.o" flags="VALUE_WORKSPACE_PATH" kind="sourcePath" name=""/>
</sourceEntries>
</configuration>
</storageModule>
<storageModule moduleId="scannerConfiguration">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-E -P -v -dD" command="" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/${specs_file}&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'g++ -E -P -v -dD &quot;${plugin_state_location}/specs.cpp&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/specs.c&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="arm-none-eabi-g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="arm-none-eabi-g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCWinStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCWinStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="cs-make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="arm-elf-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="arm-elf-g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-elf-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="arm-elf-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="arm-elf-g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCWinStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-elf-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCWinStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_YG_GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_YG_GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="arm-none-eabi-g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_YG_GCCWinStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_YG_GCCWinStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="arm-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="arm-eabi-g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="arm-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="arm-eabi-g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCWinStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCWinStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<scannerConfigBuildInfo instanceId="0.213957337">
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.make.core.GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-E -P -v -dD" command="" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/${specs_file}&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'g++ -E -P -v -dD &quot;${plugin_state_location}/specs.cpp&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.managedbuilder.core.GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-c 'gcc -E -P -v -dD &quot;${plugin_state_location}/specs.c&quot;'" command="sh" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="arm-none-eabi-g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="arm-none-eabi-g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCWinStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_CS_GCCWinStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="cs-make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="arm-elf-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="arm-elf-g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-elf-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="arm-elf-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="arm-elf-g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCWinStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-elf-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_GCCWinStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_YG_GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_YG_GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="arm-none-eabi-g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_YG_GCCWinStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-none-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_YG_GCCWinStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="arm-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="arm-eabi-g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCWinManagedMakePerProjectProfileC">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.c" command="arm-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCWinManagedMakePerProjectProfileCPP">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/specs.cpp" command="arm-eabi-g++" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCWinStandardMakePerProjectProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="specsFile">
<runAction arguments="-E -P -v -dD ${plugin_state_location}/${specs_file}" command="arm-eabi-gcc" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
<profile id="org.eclipse.cdt.cross.arm.gnu.ARM_DK_GCCWinStandardMakePerFileProfile">
<buildOutputProvider>
<openAction enabled="true" filePath=""/>
<parser enabled="true"/>
</buildOutputProvider>
<scannerInfoProvider id="makefileGenerator">
<runAction arguments="-f ${project_name}_scd.mk" command="make" useDefault="true"/>
<parser enabled="true"/>
</scannerInfoProvider>
</profile>
</scannerConfigBuildInfo>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
<storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/>
<storageModule moduleId="org.eclipse.cdt.core.language.mapping"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="cdtBuildSystem" version="4.0.0">
<project id="dongfang_FC_rewrite.null.1063235677" name="dongfang_FC_rewrite"/>
</storageModule>
</cproject>
/branches/dongfang_FC_rewrite/ADXRS610_FC2.0.c
1,18 → 1,19
#include "ADXRS610_FC2.0.h"
#include "configuration.h"
 
const uint8_t GYRO_REVERSED[3] = {0,0,0};
const uint8_t ACC_REVERSED[3] = {0,1,0};
const uint8_t GYRO_REVERSED[3] = { 0, 0, 0 };
const uint8_t ACC_REVERSED[3] = { 0, 1, 0 };
 
void gyro_calibrate(void) {}
void gyro_calibrate(void) {
}
 
void gyro_setDefaults(void) {
staticParams.GyroD = 5;
staticParams.DriftComp = 10;
staticParams.GyroAccFactor = 1;
staticParams.GyroAccTrim = 5;
staticParams.GyroD = 5;
staticParams.DriftComp = 10;
staticParams.GyroAccFactor = 1;
staticParams.GyroAccTrim = 5;
 
// Not used.
staticParams.AngleTurnOverPitch = 78;
staticParams.AngleTurnOverRoll = 78;
// Not used.
staticParams.AngleTurnOverPitch = 78;
staticParams.AngleTurnOverRoll = 78;
}
/branches/dongfang_FC_rewrite/ENC-03_FC1.3.c
8,62 → 8,68
#define PITCHROLL_MINLIMIT GYRO_SUMMATION_FACTOR_PITCHROLL * 510
#define PITCHROLL_MAXLIMIT GYRO_SUMMATION_FACTOR_PITCHROLL * 515
 
const uint8_t GYRO_REVERSED[3] = {0,0,1};
const uint8_t ACC_REVERSED[3] = {0,1,0};
const uint8_t GYRO_REVERSED[3] = { 0, 0, 1 };
const uint8_t ACC_REVERSED[3] = { 0, 1, 0 };
 
// void gyro_init(void) {}
void gyro_calibrate(void) {
uint8_t i, axis, factor, numberOfAxesInRange = 0;
uint16_t timeout;
// GyroDefectNick = 0; GyroDefectRoll = 0; GyroDefectYaw = 0;
timeout = SetDelay(2000);
uint8_t i, axis, factor, numberOfAxesInRange = 0;
uint16_t timeout;
// GyroDefectNick = 0; GyroDefectRoll = 0; GyroDefectYaw = 0;
timeout = SetDelay(2000);
 
for(i = 140; i != 0; i--) {
// If all 3 axis are in range, shorten the remaining number of iterations.
if(numberOfAxesInRange == 3 && i > 10) i = 9;
numberOfAxesInRange = 0;
for (axis=PITCH; axis<=YAW; axis++) {
if (axis==YAW) factor = GYRO_SUMMATION_FACTOR_YAW;
else factor = GYRO_SUMMATION_FACTOR_PITCHROLL;
if(rawGyroSum[axis] < 510 * factor) DACValues[axis]--;
else if(rawGyroSum[axis] > 515 * factor) DACValues[axis]++;
else numberOfAxesInRange++;
/* Gyro is defective. But do keep DAC within bounds (it's an op amp not a differential amp). */
if(DACValues[axis] < 10) {
DACValues[axis] = 10;
} else if(DACValues[axis] > 245) {
DACValues[axis] = 245;
for (i = 140; i != 0; i--) {
// If all 3 axis are in range, shorten the remaining number of iterations.
if (numberOfAxesInRange == 3 && i > 10)
i = 9;
numberOfAxesInRange = 0;
 
for (axis = PITCH; axis <= YAW; axis++) {
if (axis == YAW)
factor = GYRO_SUMMATION_FACTOR_YAW;
else
factor = GYRO_SUMMATION_FACTOR_PITCHROLL;
 
if (rawGyroSum[axis] < 510 * factor)
DACValues[axis]--;
else if (rawGyroSum[axis] > 515 * factor)
DACValues[axis]++;
else
numberOfAxesInRange++;
 
/* Gyro is defective. But do keep DAC within bounds (it's an op amp not a differential amp). */
if (DACValues[axis] < 10) {
DACValues[axis] = 10;
} else if (DACValues[axis] > 245) {
DACValues[axis] = 245;
}
}
 
I2C_Start(TWI_STATE_GYRO_OFFSET_TX); // initiate data transmission
 
// Wait for I2C to finish transmission.
while (twi_state) {
// Did it take too long?
if (CheckDelay(timeout)) {
printf("\r\n DAC or I2C Error! check I2C, 3Vref, DAC, and BL-Ctrl");
break;
}
}
 
analog_start();
 
Delay_ms_Mess(i < 10 ? 10 : 2);
}
}
I2C_Start(TWI_STATE_GYRO_OFFSET_TX); // initiate data transmission
// Wait for I2C to finish transmission.
while(twi_state) {
// Did it take too long?
if(CheckDelay(timeout)) {
printf("\r\n DAC or I2C Error! check I2C, 3Vref, DAC, and BL-Ctrl");
break;
}
}
 
analog_start();
Delay_ms_Mess(i<10 ? 10 : 2);
}
Delay_ms_Mess(70);
Delay_ms_Mess(70);
}
 
void gyro_setDefaults(void) {
staticParams.GyroD = 3;
staticParams.DriftComp = 250;
staticParams.GyroAccFactor = 10;
staticParams.GyroAccTrim = 1;
staticParams.GyroD = 3;
staticParams.DriftComp = 250;
staticParams.GyroAccFactor = 10;
staticParams.GyroAccTrim = 1;
 
// Not used.
staticParams.AngleTurnOverPitch = 85;
staticParams.AngleTurnOverRoll = 85;
// Not used.
staticParams.AngleTurnOverPitch = 85;
staticParams.AngleTurnOverRoll = 85;
}
/branches/dongfang_FC_rewrite/ENC-03_FC1.3.h
1,26 → 1,26
/*
#ifndef _ENC03_FC13_H
#define _ENC03_FC13_H
#ifndef _ENC03_FC13_H
#define _ENC03_FC13_H
 
#include "sensors.h"
/ *
#include "sensors.h"
/ *
* Configuration for the ENC-03 gyros and oriented and wired on FC 1.3 (with DAC).
* /
 
#define GYRO_HW_NAME "ENC"
#define GYRO_HW_FACTOR 1.304f
#define GYRO_HW_NAME "ENC"
#define GYRO_HW_FACTOR 1.304f
 
/ *
/ *
* Correction factor - determined experimentally: Hold the copter in the hand, and turn it 90 degrees.
* If AnglePitch or AngleRoll in debug in MK-Tool changes by x degrees, multiply the value here by x/90.
* If the hardware related contants are set correctly, flight should be OK without bothering to
* make any adjustments here. It is only for luxury.
* /
#define GYRO_PITCHROLL_CORRECTION 1.11f
#define GYRO_PITCHROLL_CORRECTION 1.11f
 
/ *
/ *
* Same for yaw.
* /
#define GYRO_YAW_CORRECTION 1.28f
#endif
*/
#define GYRO_YAW_CORRECTION 1.28f
#endif
*/
/branches/dongfang_FC_rewrite/Flight-Ctrl_MEGA644p_MK3MAG__invenSense_V0_74df_SVN0001.hex
0,0 → 1,2113
:100000000C945C040C9479040C9479040C94790499
:100010000C9479040C9479040C9479040C9479046C
:100020000C9479040C94E0130C9479040C947904E6
:100030000C9406260C9479040C9479040C9479049D
:100040000C9479040C9479040C9439130C9479046D
:100050000C94BB060C9479040C9484060C947904DB
:100060000C9438140C9479040C9498230C9479040F
:100070000C9461390C9479040C9479040A0A0D00EB
:100080004E65757472616C20284143432D4D6F6439
:1000900065290048656164696E67486F6C64000A91
:1000A0000D436F6E74726F6C3A20000A0D537570B9
:1000B000706F727420666F722047505320617420F5
:1000C0003173742055415254000A0D537570706F8E
:1000D000727420666F722047505320617420326E14
:1000E000642055415254000A0D537570706F72743C
:1000F00020666F72204D4B334D414720436F6D702A
:10010000617373000A0D3D3D3D3D3D3D3D3D3D3D2F
:100110003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D0F
:100120003D3D3D3D3D3D3D3D3D000A0D3D3D3D3D9F
:100130003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3DEF
:100140003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D001C
:100150000A0D536F6674776172653A205625642ED6
:10016000256425630070000D0A20202020204350C4
:10017000553A2041746D656761363434000A0D4884
:10018000617264776172653A20437573746F6D00B4
:100190000A0D466C69676874436F6E74726F6C0009
:1001A0000A0D3D3D3D3D3D3D3D3D3D3D3D3D3D3DE2
:1001B0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D6F
:1001C0003D3D3D3D3D00416E676C6550697463681F
:1001D000202020202020416E676C65526F6C6C20BF
:1001E000202020202020416E676C655961772020F7
:1001F0002020202020204779726F5069746368287E
:100200005049442920204779726F526F6C6C2850F6
:100210004944292020204779726F59617720202096
:100220002020202020204779726F5069746368284D
:100230004143292020204779726F526F6C6C28410E
:100240004329202020204779726F59617728414344
:10025000292020202020416363506974636820288E
:10026000616E676C6529416363526F6C6C20286115
:100270006E676C6529205542617420202020202063
:100280002020202020205069746368205465726DFE
:10029000202020202020526F6C6C205465726D202D
:1002A000202020202020596177205465726D202065
:1002B0002020202020205468726F74746C652054B4
:1002C00065726D202020307468204F20436F727259
:1002D000207069746368307468204F20436F7272B5
:1002E00020726F6C6C204472696674436F6D704449
:1002F000656C746120504472696674436F6D70441C
:10030000656C746120524144506974636847797226
:100310006F4F666673204144526F6C6C4779726F01
:100320004F66667320204D31202020202020202081
:100330002020202020204D3220202020202020207E
:100340002020202020204D3320202020202020206D
:100350002020202020204D3420202020202020205C
:10036000202020202020436F6E74726F6C596177BB
:1003700020202020202041697270726573732E2026
:1003800052616E6765204472696674436F6D705088
:100390006974636820204472696674436F6D70529B
:1003A0006F6C6C20202041697270726573734669AE
:1003B0006C746572656441697270726573734144EF
:1003C000432020202020020100070603020105022D
:1003D00001000706030201043132003131003130DF
:1003E000002025632020202D2020202D2020202DBE
:1003F0002000202563202020256320202025632045
:100400002020256320002025632020202563202034
:1004100020256320202025632000424C2D43747248
:100420006C20666F756E64200020253364202025C3
:1004300033642020253364202025336420002025C8
:100440003364202025336420202533642020253385
:1004500064200020253364202025336420202533A8
:100460006420202533642000424C2D4374726C209C
:100470004572726F7273200048693A2534692020F2
:1004800043663A253469200047733A2534692020B1
:1004900059613A25346920004E693A253469202093
:1004A000526F3A253469200045787465726E436F47
:1004B0006E74726F6C202000506F343A20253369BF
:1004C00020506F383A2025336900506F333A202589
:1004D000336920506F373A2025336900506F323A24
:1004E0002025336920506F363A2025336900506F3C
:1004F000313A2025336920506F353A202533690081
:100500004F6666436F757273653A202535690048FA
:10051000656164696E673A20202025356900436F64
:10052000757273653A2020202025356900436F6D70
:1005300070617373202020202020200052432D4C16
:100540006576656C3A2025356900566F6C74616775
:10055000653A20202533692E253169560050333AFB
:10056000253469202050343A253469200050313A2E
:10057000253469202050323A253469200047733AE7
:10058000253469202059613A25346920004E693AA2
:100590002534692020526F3A253469200043373AC8
:1005A000253469202043383A253469200043353A00
:1005B000253469202043363A253469200043333AF4
:1005C000253469202043343A253469200043313AE8
:1005D000253469202043323A25346920004865617A
:1005E00064696E673A20202025356900526F6C6C73
:1005F0003A202020202020253569004E69636B3A7F
:1006000020202020202025356900417474697475EC
:1006100064650028632920486F6C67657220427505
:100620007373004D697373696E6720424C2D437478
:10063000726C3A256400493243204572726F722110
:1006400021210053657474696E673A202564202562
:10065000730048573A5625642E25642053573A258F
:10066000642E25642563002B204D696B726F4B6FE0
:1006700070746572202B005B25695D005B25695DE8
:1006800000000047008F00D6001E016501AC01F399
:10069000013A028102C7020E0354039903DF0324C7
:1006A000046904AE04F20436057905BC05FE054074
:1006B000068206C306040744078307C20700083EF4
:1006C000087B08B708F2082D096809A109DA0912A0
:1006D0000A490A7F0AB50AE90A1D0B500B820BB4BE
:1006E0000BE40B130C420C6F0C9C0CC70CF20C1B94
:1006F0000D440D6B0D920DB70DDB0DFE0D210E425D
:100700000E610E800E9E0EBA0ED60EF00E090F214F
:100710000F380F4D0F610F740F860F970FA60FB58F
:100720000FC20FCE0FD80FE10FEA0FF00FF60FFA3E
:100730000FFE0FFF0F0010000047008F00D7001EB4
:10074000016601AF01F70140028902D2021C036772
:1007500003B203FD034A049704E40433058205D37E
:100760000524067706CB0620077607CE07270882E2
:1007700008DE083D099D09FF09640ACB0A340BA075
:100780000B0F0C800CF50C6D0DE90D680EEC0E7363
:100790000F001092102811C51168121113C2137B9B
:1007A000143C150616DA16B917A3189B19A11AB628
:1007B0001BDD1C171E671FCE205022F023B2259A86
:1007C00027AE29F62B782E3E315534CC37B63B2C4C
:1007D000404E45464B5052BE5A0565D971FF7FFFCA
:1007E0007FFF7FFF7FFF7FFF7FFF7FFF7F0A0D0A75
:1007F0000D2121204D495353494E4720424C2D4352
:1008000054524C3A20256420212100256420000AFE
:100810000D466F756E6420424C2D4374726C3A2005
:10082000000A0D3D3D3D3D3D3D3D3D3D3D3D3D3D98
:100830003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3DE8
:100840003D000A0D4D697865722D436F6E666967CC
:100850003A202725732720282575204D6F746F7245
:100860007329000A0D47656E65726174696E6720B1
:1008700064656661756C74204D6978657220546199
:10088000626C65000A0D5573696E67205061726174
:100890006D6574657220536574202564000A0D49E6
:1008A0006E697420506172616D6574657220696E45
:1008B00020454550524F4D0011241FBECFEFD0E1CF
:1008C000DEBFCDBF12E0A0E0B1E0EAECF2E802C08A
:1008D00005900D92AA32B107D9F716E0AAE2B2E06C
:1008E00001C01D92A033B107E1F70E947B040C9474
:1008F00063410C9400000F931F93CF93DF93F89400
:100900000E941F3E8093ED020E942E3E982F8093FE
:10091000DC0184B7877F84BF809160008861809309
:100920006000109260009A3009F4A3C1943109F478
:10093000A0C1289A0E94FF1F0E94C1120E94B013FA
:100940000E940F088091ED02813011F40E94063957
:100950000E94D2250E94EA130E9433230E94E63FA0
:10096000789400D00F92ADB7BEB711961C92119734
:1009700080EA91E013969C938E9312970E94890FC0
:10098000EDB7FEB7118280E991E0938382830E94E4
:10099000890FADB7BEB711961C9211978DE791E004
:1009A00013969C938E9312970E94890FEDB7FEB712
:1009B000118287E691E0938382830E94890F0F90D2
:1009C0000F900F908091ED02813091F400D00F9242
:1009D000ADB7BEB711961C92119785E691E01396BC
:1009E0009C938E9312970E94890F0F900F900F90F7
:1009F000EDB7FEB739970FB6F894FEBF0FBEEDBF47
:100A00003196ADB7BEB711961C9280E591E0928306
:100A10008183148213828AE490E09683858385EC37
:100A200090E0908787830E94890FEDB7FEB73696D6
:100A30000FB6F894FEBF0FBEEDBF11828AE291E0BF
:100A4000938382830E94890F0F900F900F900E94D2
:100A5000333888EC90E00E94EF12EC0142988091CC
:100A6000DC018C3008F009C129988A3009F403C1EF
:100A7000843109F400C12898CE010E94F91288231C
:100A8000D9F388EC90E00E94EF12EC01429A43986F
:100A90008091DC018A3009F4F4C0843109F4F1C09A
:100AA000289A8C3008F0EBC0299ACE010E94F912E6
:100AB0008823D9F388EC90E00E94EF12EC01CE017C
:100AC0000E94F9128823D9F3439A0E94242500D06A
:100AD0000F92ADB7BEB711961C92119784E091E0CA
:100AE00013969C938E9312970E94890FEDB7FEB7D1
:100AF000118287EE90E0938382830E94890F0F908A
:100B00000F900F908091ED02813009F4EAC000D07F
:100B10000F92EDB7FEB711828BEA90E09383828348
:100B20000E94890F0F900F900F900E9402220E9446
:100B300062300E94D8130E94453680ED97E00E94F3
:100B40005E3E00D00F92ADB7BEB711961C921197C2
:100B50008FE990E013969C938E9312970E94890FD1
:100B6000809172050F900F900F9082FFA7C000D068
:100B70000F92EDB7FEB7118283E990E093838283F1
:100B80000E94890F0F900F900F9000D00F92EDB739
:100B9000FEB711828CE790E0938382830E94890FD5
:100BA0000F900F900F900E94001A88E893E19093A5
:100BB00084018093830105E010E080915302882333
:100BC000E1F3809116018823C1F3109253025C9ADD
:100BD0000E9426315C982091DC012A3009F465C01E
:100BE000243109F462C0289A809183019091840194
:100BF0000197909384018093830180918301909168
:100C00008401892B09F43FC080918F028823D9F594
:100C10002A3009F44EC0243109F44BC0289A80913F
:100C20005302882321F080918A0280FD02C00E9435
:100C30009F090E940A0DCE010E94F9128823B1F08B
:100C400080911401909115011816190654F4209101
:100C50001401309115018091830590E02817390720
:100C600054F184E190E00E94EF12EC010E947F2099
:100C7000A4CF28985FCE289AFFCE299AF6CE29983D
:100C800014CF28980ECF2A3091F0243181F0289883
:100C90008091830190918401892B09F60E946F2332
:100CA0001093840100938301BACF28989DCF289A8E
:100CB000EFCF2898B4CF0E94913ED3CF00D00F92AF
:100CC000ADB7BEB711961C92119780E890E01396CD
:100CD0009C938E9312970E94890F0F900F900F9004
:100CE00054CF00D00F92ADB7BEB711961C9211979A
:100CF00089EC90E013969C938E9312970E94890F33
:100D00000F900F900F9011CF1F920F920FB60F926E
:100D100011248F939F93EF93FF9380910101882378
:100D2000A9F480914F029091500201969093500245
:100D300080934F02FC01E851FC4FE081ED3099F0C7
:100D40008639910581F0E093C60004C010925002EC
:100D500010924F02FF91EF919F918F910F900FBED4
:100D60000F901F9018951092500210924F0281E040
:100D700080930101E8CF1F920F920FB60F921124BA
:100D80002F933F934F935F936F938F939F93AF9363
:100D9000BF93CF93DF93EF93FF936091C600809151
:100DA0003402882351F430914C023323C1F0363998
:100DB000C8F010924C0210923402FF91EF91DF9133
:100DC000CF91BF91AF919F918F916F915F914F9113
:100DD0003F912F910F900FBE0F901F901895633287
:100DE00009F43FC06D3099F0E32FF0E0EC50FD4F77
:100DF00060833F5F30934C0280914D0290914E0290
:100E0000860F911D90934E0280934D02D6CFA32F53
:100E1000B0E0FD01EE50FD4F9081ED01CD50DD4F72
:100E2000888140914D0250914E02491B5109481B47
:100E300051095F7050934E0240934D022081CA01C8
:100E40000024880F991F001C880F991F001C892FF0
:100E5000902D835C281789F01092340210924C0276
:100E6000ACCF6093F40281E080934C0283E290E087
:100E700090934E0280934D02A0CF9881842F8F7360
:100E8000835C981749F7AC50BD4F6C933F5F30932C
:100E9000350281E0809334028091F6028235F1F6CA
:100EA0002CE088E190E00FB6F894A895809360005C
:100EB0000FBE20936000D2CFCF93DF93BC01009789
:100EC000A9F120E030E040E050E0FA01E851FC4FA9
:100ED0008081280F311D4F5F5F4F46175707A8F3DA
:100EE0003F70C9010024880F991F001C880F991FAB
:100EF000001C892F902D835CDB0111962F73235CDE
:100F0000ED012196FB01E851FC4F8083A851BC4FB5
:100F10002C93C851DC4F8DE08883109201018091A1
:100F2000E8038093C600DF91CF910895E0E0F0E000
:100F30008DE3A1E0B0E02DE3C2E0D0E0E4CF50913A
:100F40003502565009F457C033E043E01EC0972FD6
:100F50009D53F0E02295207F892F86958695282B3A
:100F6000EC50FD4F2083E42FEE5F5230C1F153501F
:100F7000F0E09295990F990F907C6D53962BEC5061
:100F8000FD4F90834D5F5523A1F1E32FF0E0EC502E
:100F9000FD4F80813F5FE32FF0E0EC50FD4F20815B
:100FA0002D533F5FE32FF0E0EC50FD4F70813F5F2A
:100FB000E32FF0E0EC50FD4F60813F5F922F929560
:100FC0009F708D53880F880F892BE42FF0E0EC5031
:100FD000FD4F8083E42FEF5F513009F0B8CFE3502D
:100FE00087EF92E09093370280933602E0933802C5
:100FF0000895E42FF4CFE0E0F3CF1F93182F8A3049
:1010000051F08091C00085FFFCCF1093C60080E0B6
:1010100090E01F9108958DE00E94FD07F2CF0F939D
:101020001F930FB7F8948091C1008F778093C10010
:101030008091C1008F7B8093C100589A5098599A33
:10104000519A1092C5008AE28093C4008091C0003A
:1010500082608093C00088E18093C1008091C200CB
:101060008F778093C2008091C2008F7B8093C200F3
:101070008091C2008F7D8093C2008091C2008F7EDC
:101080008093C2008091C200877F8093C2008091CC
:10109000C1008B7F8093C1008091C20084608093E7
:1010A000C2008091C20082608093C2008091C00023
:1010B00087FF06C08091C6008091C00087FDFACFEF
:1010C0008091C10080688093C1008091C1008064DC
:1010D0008093C10080910201909103010E94EF1260
:1010E00090937F0480937E04109234021092370212
:1010F000109236021092380211E0109301018CED2B
:1011000090E00E94EF1290938B0380938A031092D9
:101110009C038AE480939D0384E68093A0038AE085
:1011200080939E0310939F030FBF1F910F9108950B
:10113000BF92CF92DF92EF92FF920F931F93DF93B4
:10114000CF93CDB7DEB78D852E8593E29093E803DC
:101150008F598093E9038C858093EA03222379F4E5
:1011600063E070E0CB010E945C07CF91DF911F919B
:101170000F91FF90EF90DF90CF90BF900895EF8494
:10118000F88803E1C02ED12CCC0EDD1E49895A8986
:101190004115510529F3022F015063E070E010E082
:1011A00062C0A12FB0E01F5FFA01AE0DBF1D8C9190
:1011B000AF014150504009F48BC0E12FF0E01F5FB8
:1011C000EE0DFF1DA0814150504009F06DC000237D
:1011D00009F46AC096012E5F3F4FF601E080F1806E
:1011E00012E0C12ED12CC20ED31EF90140815181D3
:1011F0000150382F32953F7090E08F7090702A2FF9
:101200002295269526952370880F991F880F991F80
:10121000282B235CAF73A35C10E08B2D86958695FD
:10122000835CFB01E851FC4F80838B2D90E0837041
:10123000907082959295907F9827807F9827382B81
:10124000335CFB01E751FC4F3083FB01E651FC4F5F
:101250002083FB01E551FC4FA0836C5F7F4F41155C
:10126000510509F47FCFF701E10FF11DB0801F5F39
:101270004150504009F095CF002391F0F60132968D
:10128000D601ED90FC9012E0C12ED12CCE0EDF1EC7
:101290000190F081E02D0150309709F04CC010E032
:1012A00030E02DE3ADE3B9CF382F32953F7090E0B9
:1012B0008F7090702A2F2295269526952370880F7F
:1012C000991F880F991F282B235CAF73A35CA5CFB0
:1012D000002371F4382F32953F7090E08F7090703A
:1012E000880F991F880F991F282F235CADE395CF96
:1012F000F6013296D601ED90FC90A2E0CA2ED12CD8
:10130000CE0EDF1E4081518101504115510521F063
:10131000E0E0F0E011E054CF382F32953F7090E0DC
:101320008F709070880F991F880F991F282F235C4A
:1013300010E0ADE372CFA0E0B0E011E036CF0F9344
:101340001F93DF93CF93CDB7DEB760970FB6F894B6
:10135000DEBF0FBECDBF80910101882309F4BAC062
:1013600080912A02882329F080910101882309F0C5
:10137000A0C180912C02882329F08091010188234B
:1013800009F04DC280912D02882329F0809101013E
:10139000882309F0E1C1609100016F3F09F441C069
:1013A00070E062957295707F7627607F76276A532A
:1013B0007E4F8E010F5F1F4FC80140E150E00E9439
:1013C00012418DB79EB70B970FB6F8949EBF0FBE14
:1013D0008DBFEDB7FEB7319681E4ADB7BEB71196BC
:1013E0008C9381E0818382E0828380E091E094832A
:1013F000838381E090E0968385831087078380E173
:1014000090E0928781870E9498088FEF8093000177
:101410002DB73EB7255F3F4F0FB6F8943EBF0FBEC6
:101420002DBF80918004882329F0809101018823B9
:1014300009F0CCC18091020190910301892B09F040
:1014400054C080912E02882329F0809101018823C5
:1014500009F0ADC280914A0290914B02892B09F0AC
:1014600021C280912F02882329F0809101018823D5
:1014700009F022C280912B02882329F0809101017A
:10148000882309F040C180918A0390918B030E94C8
:10149000F912882329F080910101882309F097C06F
:1014A00080913102882329F080910101882309F07D
:1014B00079C080913002882329F08091010188232E
:1014C00009F046C080913202882321F08091010109
:1014D0008823A9F460960FB6F894DEBF0FBECDBF87
:1014E000CF91DF911F910F91089580917E0490918B
:1014F0007F040E94F912882309F0A7CFA2CF8DB7ED
:101500009EB707970FB6F8949EBF0FBE8DBFEDB77D
:10151000FEB7319688E5ADB7BEB711968C9381E0E2
:10152000818382838DED92E09483838380E190E0D8
:10153000968385830E949808109232022DB73EB799
:10154000295F3F4F0FB6F8943EBF0FBE2DBFC2CFED
:101550002DB73EB7275030400FB6F8943EBF0FBEB0
:101560002DBFEDB7FEB7319680E5ADB7BEB711968A
:101570008C9381E08183828388E195E094838383E7
:1015800084E190E0968385830E949808109230024F
:101590002DB73EB7295F3F4F0FB6F8943EBF0FBE41
:1015A0002DBF90CF00D00F92EDB7FEB7319684E5F6
:1015B000ADB7BEB711968C9381E0818312820E94F1
:1015C0009808109231020F900F900F9072CF609197
:1015D0004E0570914F0580915005909151052AE07C
:1015E00030E040E050E00E94834024E736E040E0F5
:1015F00050E00E94F740309329062093280660911E
:1016000052057091530580915405909155052AE03B
:1016100030E040E050E00E94834024E736E040E0C4
:1016200050E00E94F74030932B0620932A068091C9
:10163000BF0180932C068091C00180932D0680917C
:101640009D0280932E068DB79EB707970FB6F8942C
:101650009EBF0FBE8DBFEDB7FEB7319687E7ADB722
:10166000BEB711968C9383E0818381E0828388E208
:1016700096E09483838388E090E0968385830E943C
:1016800098082DB73EB7295F3F4F0FB6F8943EBF7D
:101690000FBE2DBF80919D02853010F010929D02EB
:1016A00083E690E00E94EF1290938B0380938A036D
:1016B000F7CE2DB73EB7275030400FB6F8943EBF57
:1016C0000FBE2DBFEDB7FEB7319686E5ADB7BEB7FD
:1016D00011968C9381E0818382838CE993E09483DB
:1016E00083838AE090E0968385830E949808109215
:1016F0002A022DB73EB7295F3F4F0FB6F8943EBF81
:101700000FBE2DBF36CE8DB79EB707970FB6F89494
:101710009EBF0FBE8DBFEDB7FEB7319687E4ADB764
:10172000BEB711968C9381E08183828388EB94E02D
:10173000948383838BE090E0968385830E9498084E
:1017400010922B022DB73EB7295F3F4F0FB6F8948A
:101750003EBF0FBE2DBF97CE0E94091A8DB79EB710
:101760000F970FB6F8949EBF0FBE8DBFEDB7FEB7B3
:1017700031968CE4ADB7BEB711968C9381E081832E
:1017800083E0828385E792E09483838321E030E0E5
:101790003683258382E391E0908787833287218790
:1017A00083E391E09487838780E590E0968785873F
:1017B0000E94980810922D022DB73EB7215F3F4F2F
:1017C0000FB6F8943EBF0FBE2DBFE5CD8DB79EB7C7
:1017D00007970FB6F8949EBF0FBE8DBFEDB7FEB74B
:1017E000319682E4ADB7BEB711968C9381E08183C8
:1017F000828380E894E09483838381E090E0968301
:1018000085830E949808109280042DB73EB7295F07
:101810003F4F0FB6F8943EBF0FBE2DBF0BCE0E94B8
:10182000091A8DB79EB70B970FB6F8949EBF0FBEDF
:101830008DBFEDB7FEB7319688E4ADB7BEB7119650
:101840008C9381E0818382E0828383E392E09483BE
:10185000838381E090E0968385838091330224E145
:10186000829FC00111248D5C9E4F9087878384E105
:1018700090E0928781870E949808809133028F5F61
:10188000809333022DB73EB7255F3F4F0FB6F894D4
:101890003EBF0FBE2DBF843010F010923302109265
:1018A0002C0270CD80919A0390919B030E94F912B3
:1018B000882309F0DACDD5CD8DB79EB707970FB63F
:1018C000F8949EBF0FBE8DBFEDB7FEB7319683E48F
:1018D000ADB7BEB711968C9381E0818382838CE88B
:1018E00093E0948383838EE090E0968385830E94C7
:1018F000980860914E0570914F0580915005909128
:1019000051052AE030E040E050E00E94834024E7A7
:1019100036E040E050E00E94F74030938D03209382
:101920008C036091520570915305809154059091FC
:1019300055052AE030E040E050E00E94834024E773
:1019400036E040E050E00E94F74030938F03209350
:101950008E0360914A0570914B0580914C059091E2
:101960004D052AE030E040E050E00E94834026E848
:1019700032E040E050E00E94F74030939103209322
:1019800090032DB73EB7295F3F4F0FB6F8943EBF87
:101990000FBE2DBF80914A0290914B020E94EF1220
:1019A00090939B0380939A0310922F0263CD8DB77F
:1019B0009EB707970FB6F8949EBF0FBE8DBFEDB7C9
:1019C000FEB7319684E4ADB7BEB711968C9381E033
:1019D0008183828386EA93E09483838382E490E028
:1019E000968385830E9498082DB73EB7295F3F4FA5
:1019F0000FB6F8943EBF0FBE2DBF809102019091AB
:101A000003010E94EF1290937F0480937E04109252
:101A10002E0220CD0F931F93DF93CF9300D0CDB72D
:101A2000DEB780913902882319F081508093390202
:101A300080913402882339F40F900F90CF91DF9179
:101A40001F910F9108950E949F078091F5028236A1
:101A5000B9F18091F602873609F47CC1883680F0AE
:101A60008C3609F451C18D3608F4CFC0863709F49D
:101A70006DC1883709F0CCC081E080933202C8C0C4
:101A8000823609F46BC1833608F4D1C0833609F479
:101A900049C1843609F0BCC0E0913602F0913702AA
:101AA00080812AE0829FC0011124909303018093DA
:101AB0000201892B09F4ACC081E080932E02A8C0FA
:101AC0008091F602803709F470C18137A0F48D3619
:101AD00009F4E4C08E3609F46EC08B3409F0B9CF36
:101AE000E0913602F09137028081918190938801D4
:101AF00080938701AECF833709F4ABC0843709F4F4
:101B000058C1813709F0A5CF0091360210913702F4
:101B1000D8018C918F3F09F480C1D8018C91882322
:101B200009F06FC181E08C93009136021091370269
:101B3000D8018C910E94BF37E0913602F0913702B4
:101B4000E0818BE48A83809101018823E1F3E983BA
:101B5000EDB7FEB73F970FB6F894FEBF0FBEEDBFCF
:101B6000319681E5ADB7BEB711968C9381E0818344
:101B700083E08283CE0101969483838321E030E069
:101B800036832583CE01029690878783328721870B
:101B90008AE695E0948783878DE590E09687858730
:101BA0000E949808EDB7FEB73F960FB6F894FEBFB7
:101BB0000FBEEDBF4ECF809101018823E1F38DB7B9
:101BC0009EB707970FB6F8949EBF0FBE8DBFEDB7B7
:101BD000FEB731968EE4ADB7BEB711968C9381E017
:101BE0008183828387EC95E0948383838DE490E006
:101BF000968385830E949808EDB7FEB737960FB697
:101C0000F894FEBF0FBEEDBF24CF883609F4B8C0EC
:101C1000109237021092360210923802109234025B
:101C20000F900F90CF91DF911F910F910895813602
:101C300079F7E0913602F0913702808180930001BC
:101C4000803218F08FE1809300018FEF8093C304FE
:101C5000DFCF80918A0280FDFCCE00913602109188
:101C60003702D8018C91882339F08C91863020F48A
:101C700011968C918B34A9F11982809101018823EE
:101C8000E1F38DB79EB707970FB6F8949EBF0FBECE
:101C90008DBFEDB7FEB7319683E515C0E0913602F2
:101CA000F09137028081813009F4C2C019828DB76A
:101CB0009EB707970FB6F8949EBF0FBE8DBFEDB7C6
:101CC000FEB731968DE4ADB7BEB711968C9381E027
:101CD00081838283CE0101969483838381E090E0A7
:101CE00087CFAAE6B5E0F80132968DE501900D9216
:101CF0008150E1F7F80180810E948B370E941A37EA
:101D000089830E94B73EB9CF8FEF8093C304E091DF
:101D10003602F091370280818093750281E08093D2
:101D20002D0276CFE0913602F091370280812AE0D1
:101D3000829FC001112490934B0280934A02892B09
:101D400009F466CF81E080932F0262CF81E0809317
:101D50002A025ECF81E080932B025ACFA8EBB4E039
:101D600080913602909137029C01F9018BE001903D
:101D70000D928150E1F78091C1048093800465CF7A
:101D80008FEF8093C304E0913602F0913702808197
:101D900090917602892B80937602882311F010921D
:101DA000330281E080932C0233CF81E080933002B4
:101DB00050CE80913802853198F0AAE3B2E080914C
:101DC0003602909137029C01F90180E101900D9259
:101DD0008150E1F78FEF809339028093C30439CEAD
:101DE000E0913602F091370280819181A281B38126
:101DF00080933A0290933B02A0933C02B0933D0241
:101E0000E9CFF8018081863008F492CE85E08083A6
:101E100000913602109137028BCE82E090E00E9452
:101E20000437F8018083009136021091370275CE95
:101E3000A7ECB5E08DE401900D928150E1F70E948E
:101E40006437809101018823E1F381E089832FCFFA
:101E5000982F80918104813021F0892F0E94FD0705
:101E6000089580917702E82FF0E0ED5CFE4F9083BB
:101E70008F5F8093770281E008951F93182F1816C3
:101E800034F480E30E94280F11501116D4F31F91EF
:101E900008951F93182F181634F480E20E94280F1B
:101EA00011501116D4F31F910895EF92FF920F93E2
:101EB0001F93CF93DF937C018B016115710569F04E
:101EC000C0E0D0E0F701EC0FFD1FE4918E2F0E94DF
:101ED000280F2196C017D107A9F7DF91CF911F9145
:101EE0000F91FF90EF9008950F931F93CF93DF937F
:101EF0008C01EB016115710539F0F80181918F01B9
:101F00000E94280F2197C9F7DF91CF911F910F9160
:101F100008952F923F924F925F926F927F928F928D
:101F20009F92AF92BF92CF92DF92EF92FF920F9368
:101F30001F93DF93CF93CDB7DEB7EA970FB6F89430
:101F4000DEBF0FBECDBF61962FAD619762963FADEC
:101F5000629760968FAD60978093810442E5A42ECE
:101F6000B12CAC0EBD1EC9018C016624772443013F
:101F70009E01245D3F4F3AAF29AFF801F490FF2056
:101F8000A9F0F5E2FF1691F0680103C0F5E2FF1633
:101F900039F00894C11CD11CF601F490FF20B1F770
:101FA000B601601B710B09F075C08601FF2009F4B2
:101FB00095C20F5F1F4F1982EE24552444244A9482
:101FC000F8010F5F1F4FF490AE2DB0E0A170B0701C
:101FD00025E7F21609F446C08F2D8062883709F490
:101FE00041C06501F0E2FF1609F44DC023E2F2168C
:101FF00009F495C04AE2F41609F495C05DE2F516BD
:1020000009F4A0C0FBE2FF1609F441C02EE2F2166B
:1020100009F444C0E0E3FE1609F496C08F2D815305
:10202000893008F097C020E030E0C901880F991F7F
:10203000880F991F880F991F220F331F280F391FF0
:102040002F0D311D20533040F8010F5F1F4FF490CA
:102050008F2D80538A3048F3522E560125E7F21611
:1020600009F0BACF109709F445C094E0C92ED12CDD
:10207000CA0CDB1CF5016080718082809380F0E2E5
:10208000FF1609F0B3CF8981882309F046C0F98291
:10209000560196CFC8010E94550F87CFF8010F5FF8
:1020A0001F4F94919A3209F45FC0892F80538A3070
:1020B00080F5692F20E030E0C901880F991F880F53
:1020C000991F880F991F220F331F280F391F260FC2
:1020D000311D20533040F8010F5F1F4F6491862F50
:1020E00080538A3048F3A90137FD10C0442EF62EE4
:1020F0005601B4CF82E0C82ED12CCA0CDB1CF501EE
:10210000808191813C01882499246CCF4FEF5FEF4F
:10211000EDCFF92E44245601A1CF560151CF38E01E
:10212000E32A56014DCFA2E0AA2EB12CAC0CBD1C67
:10213000D6015C9057FE44CF5194B0E1EB2AEFED0D
:10214000EE223ECF5601F9CFE4FCE7CFF0E2EF2AD2
:10215000560136CF28E6F216B9F04CE6F416C1F473
:1021600051E0E52A56012CCFF2E0AF2EB12CAC0C99
:10217000BD1CD6014D915C9157FD02C0442E20CF6D
:102180004FEF5FEF442E1CCF34E0E32A560118CF07
:102190008F2DF60193E6F91609F405C1843409F48C
:1021A00072C0843609F471C0893609F46EC08F3468
:1021B00009F47AC18F3609F474C1803709F479C102
:1021C000B3E7FB1609F430C155E5F51609F4D4C19F
:1021D00085E7F81609F4CCC1E8E5FE1609F4F8C065
:1021E000F8E7FF1609F4F4C0FF2009F477C1FC8278
:1021F00019822E2D30E03DAB2CAB5601EE2434E09D
:10220000232E312C2C0E3D1E81E091E0E0E021E0F8
:10221000C22ED12C2981222381F18F5F482E4E0EB0
:102220008CA99DA98073907098AF8FAB892B29F4EE
:10223000852D84190E94490F29812223B9F49CA974
:1022400096FD8CC1EFA9F8ADB09709F482C18E2D2F
:102250000E943D0FC101B6010E94740FFCA9F4FF5A
:102260008CCE852D84190E94490F87CECE01019610
:1022700061E070E00E94740FE5CF5CA956FFCECFFD
:10228000892F8E5FCBCFB1E0EB2AE0FE54C1B4E0E2
:10229000AB2EB12CAC0CBD1CF6016080718082802D
:1022A000938097FC3BC1BAE0BEAB47FC02C05FED38
:1022B000E5227CE2272E312C2C0E3D1E6114710488
:1022C0008104910409F452C09EA9892F90E0A0E0F6
:1022D000B0E088AB99ABAAABBBAB6CE2C62ED12CFD
:1022E000CC0EDD1E6CA67DA68EA69FA62AC050E34E
:1022F000352E360ED6013E926D016CA57DA58EA5BC
:102300009FA528A939A94AA95BA90E94D540B9016E
:10231000FA01C901DA013C014D012CA53DA54EA5EC
:102320005FA588A999A9AAA9BBA9281739074A07AF
:102330005B0708F440C0CB01DF018CA79DA7AEA7C7
:10234000BFA76CA57DA58EA59FA528A939A94AA9D7
:102350005BA90E94D5406A3050F247E5342E360E14
:1023600048E5F41639F65FED3522C4CF442089F4F0
:10237000AE2DB0E0BDABACAB80E090E0442DE42EE0
:10238000E91AE7FCC4C0EE2DC82EDD24C7FCD094AA
:1023900041CF3EA9232F30E040E050E028AB39ABDD
:1023A0004AAB5BAB9ACFA2E0B0E0CA0EDB1E8081E5
:1023B0008C8319821ECF9EA99830D1F0AE2DB0E04B
:1023C000BDABACABB9ADBC198B2F9B2F1601D6CFD3
:1023D000E3FE1AC06114710481049104A9F020E4A1
:1023E000E22A8F2D30E13EAB1982F82E56015DCFE7
:1023F000EE2DF0E0FDABECABE3FC0AC0F9ADFC194F
:102400008F2F9F2F1601BACF8F2D40E14EABECCF0F
:1024100020E3321609F45CC0F60140E3429389AD33
:102420008E1B982F1F01AACFF60120803180211426
:10243000310489F4F8E2FC832EE62D8335E73E83F0
:102440008CE68F83888789E289871A86F4E02F2EAD
:10245000312C2C0E3D1E47FC1CC0442D552747FD3A
:102460005095C10160E070E00E941B41009719F097
:10247000821948160CF4842DE2E0AE2EB12CAC0C7F
:10248000BD1C1982982F4E2D50E05DAB4CAB40E047
:1024900076CFF10101900020E9F731978E2F821954
:1024A000EBCF28E02EABA0CF31E0E32A48E04EABE3
:1024B0009BCF82E090E0C80ED91E808191813C01C3
:1024C0008824992490E4E92A88E7A0E1AEAB8CCF78
:1024D00039AD3C19832F932F160150CFEA960FB6D2
:1024E000F894DEBF0FBECDBFCF91DF911F910F914A
:1024F000FF90EF90DF90CF90BF90AF909F908F9024
:102500007F906F905F904F903F902F900895C82ECE
:10251000DD24C7FCD094EE24E0E07CCE909480943F
:1025200070946094611C711C811C911CEDE2E98324
:10253000FAE0FEABBACEA2E0AA2EB12CAC0CBD1CC8
:10254000D6018D919C913C01882477FC8094982C35
:10255000A8CE852D84190E943D0F79CEA0E3AA83D1
:10256000FB82CE01029662E070E00E94740F6ACE98
:102570008F2D9AE09EAB38CFA1E0EA2ABAE0BEAB3D
:1025800033CF9FB7F8948091DC018A3029F13F9ACC
:10259000479884B1886184B985B1877E85B984B54F
:1025A0008F7A84BD84B5836A84BD85B5877385BD04
:1025B00085B5887F826085BD17BC88E788BD16BC5D
:1025C00080916E00897F80936E0080916E008160A3
:1025D00080936E009FBF0895529A5A98DACF209147
:1025E00051023091520221503040280F391FC90149
:1025F00008952091510230915202821B930B8070FA
:102600009078892F089520915102309152022150E3
:102610003040280F391F8091510290915202A90138
:10262000481B590BCA01807090789923A1F3089533
:10263000209151023091520221503040280F391F11
:102640008091510290915202A901481B590BCA0175
:1026500080709078992361F480911601882381F32A
:102660001092160180917A00886C80937A00E8CFEE
:1026700008951F920F920FB60F9211242F933F933C
:102680004F935F936F937F938F939F93AF93BF937A
:10269000EF93FF93809158028150809358028F5F8F
:1026A000A9F489E0809358028091060191E089277E
:1026B00080930601882309F44CC0809151029091C7
:1026C00052020196909352028093510280915602D9
:1026D00090915702892B89F180915602909157026F
:1026E00001979093570280935602209156023091A1
:1026F0005702809104019091050182239323892B35
:1027000011F18091DC018A3039F1479A809172058C
:10271000887211F00E94F03FFF91EF91BF91AF914D
:102720009F918F917F916F915F914F913F912F91E9
:102730000F900FBE0F901F9018958FEF9FEF909303
:102740000501809304018091DC018A3039F04798BB
:10275000DDCF90935302B1CF5A9AD8CF5A98D6CFA3
:102760009FB7F894579A5F983E9A469AA0EBB0E0CC
:102770008C918F708C938C9183608C93E1EBF0E063
:1027800080818B73808380818B6080831092B20004
:102790008FEF8093B3008C9180688C93E0E7F0E03A
:1027A00080818A7F80838081826080839FBF08953B
:1027B00081E080935D02089510925D02469A08952B
:1027C0001F920F920FB60F9211240F900FBE0F9011
:1027D0001F9018959FB7F89411B812B88FEF809397
:1027E0007E00ECE7F0E080818F7180838081807EC5
:1027F00082608083AAE7B0E087E08C93EBE7F0E0AB
:102800008081887F80838C91886C8C939FBF089592
:102810009C01FB018081918182179307ACF06627B0
:102820007727621B730B80819181861797074CF085
:102830008081918150E04817590748F01182108239
:102840000895718360830895318320830895808182
:102850009181841B950B91838083089547B52091C6
:102860001301249F90011124280F391FC9010895D5
:102870001F920F920FB60F9211248F929F92BF92C8
:10288000CF92DF92EF92FF920F931F932F933F937C
:102890004F935F936F937F938F939F93AF93BF9368
:1028A000CF93DF93EF93FF93E0913101F0E020911C
:1028B000780030917900EE0FFF1FEC59FD4F8081B9
:1028C0009181820F931F9183808360917402B62E51
:1028D000B394B09274026D3009F4B4C16E3008F054
:1028E00042C06B3009F496C16C3008F462C180912B
:1028F0002602882309F40BC280910D0190910E01EC
:102900002091720230917302821B930B9093830487
:102910008093820440915E0250915F0280919D04F9
:10292000209182043091830460919D0490E001978E
:10293000DC01A49FC001A59F900DB49F900D1124B0
:10294000820F931F70E00E94C24070935F026093F9
:102950005E02809182049091830463E974E041E017
:102960000E940814AFC0613108F0DCC06F3008F479
:1029700037C16F50C62FD0E0E2E0F0E0EC1BFD0B5A
:10298000EE0FFF1FEC59FD4F808191816E01CC0C41
:10299000DD1CF601E956FB4F918380832081318154
:1029A0008091720587FDD5C203E2802E02E0902E51
:1029B0008C0E9D1ED4018C91882309F48CC1F601E4
:1029C000E95FFE4F0190F081E02DE21BF30BEE0F6B
:1029D000FF1FEE0FFF1FAFEAEA2EA4E0FA2EEC0C69
:1029E000FD1CD7012D913C918091A90490E00197A5
:1029F000AC01249FC001259F900D349F900D1124A0
:102A00006091A9048E0F9F1F70E00E94C2408B014D
:102A1000CC0FDD1FC857DB4FCB01BE0145E00E9444
:102A20000814F601E157FB4F408151818091A804C1
:102A3000D7012D913C916091A80490E00197DC01B1
:102A40004A9FC0014B9F900D5A9F900D1124821BED
:102A5000930B800F911F70E00E94C24071836083CE
:102A6000F70111830083F601E956FB4F2081318184
:102A7000D4018C91882309F421C1F601E95FFE4F4E
:102A800040815181421B530B440F551F440F551F6A
:102A9000F601E256FB4F208131818091AE046091B6
:102AA000AE0490E00197DC012A9FC0012B9F900D9E
:102AB0003A9F900D1124840F951F70E00E94C24030
:102AC00071836083EB2DF0E0EA53FC4FE491E093D7
:102AD000310180917C00807EE82BE0937C00BB205C
:102AE00029F080917A00886C80937A00FF91EF91B1
:102AF000DF91CF91BF91AF919F918F917F916F9116
:102B00005F914F913F912F911F910F91FF90EF9007
:102B1000DF90CF90BF909F908F900F900FBE0F903F
:102B20001F901895613171F68091140190911501F3
:102B30009C01220F331F280F391F80916C02909146
:102B40006D0263E070E00E94AE40260F371F36959D
:102B50002795369527953093150120931401809180
:102B60001401909115019093BF038093BE0381E0FF
:102B70008093160180916202909163020196909376
:102B800063028093620210927402E4E6F2E0119212
:102B90001192B2E0E437FB07D1F7E6ECF3E0E49101
:102BA000E093310180917C00807EE82BE0937C00F3
:102BB0009DCF683009F086CF80912802882309F4E0
:102BC000B5C0809111019091120120916E02309157
:102BD0006F02821B930B909387048093860472CFBD
:102BE00080912F0190913001009709F4AEC00197B8
:102BF0009093300180932F0187B58093DE0310926C
:102C0000DF038091A6049091A7049093E70380933B
:102C1000E60358CF209164023091650230939C0402
:102C200020939B0480912502882309F467C1809139
:102C30000B0190910C01821B930B90938D04809358
:102C40008C0440CF80912702882309F451C08091E1
:102C50000F01909110012091700230917102821B3E
:102C6000930B90938504809384044091600250916B
:102C7000610280919D0420918404309185046091CB
:102C80009D0490E00197FC01E49FC001E59F900D39
:102C9000F49F900D1124820F931F70E00E94C24098
:102CA0007093610260936002809184049091850426
:102CB00065E974E041E00E94081404CFF601E95F81
:102CC000FE4F80819181A901481B590B440F551F6C
:102CD000440F551FDDCEF601E95FFE4F80819181E3
:102CE000F901E81BF90BEE0FFF1FEE0FFF1F73CE6C
:102CF00020910F013091100180917002909171022A
:102D0000821B930B9093850480938404AECF209113
:102D10000D0130910E018091720290917302821B1D
:102D2000930B9093830480938204F4CD209111013E
:102D30003091120180916E0290916F02821B930B71
:102D40009093870480938604BDCEE0916A02F0914F
:102D50006B0221E0E039F20708F4DBC036E0EF3621
:102D6000F307D8F027B56091130170E0660F771F65
:102D7000660F771F8EED94E00E94C240620F711DB6
:102D8000603F71050CF063C187B5AB01481B510969
:102D90005093300140932F0167BD27B580911301F7
:102DA000829FC00111248E0F9F1F9093A7048093D0
:102DB000A60487B58093DE031092DF038091A604FA
:102DC0009091A7049093E7038093E6038091130109
:102DD0002091A6043091A7046FE0869FC0011124C2
:102DE0002817390708F0C5C0E0901301209113019E
:102DF0004091A6045091A7048091A2049091A3044D
:102E0000A091A404B091A504E69E700111240027AE
:102E1000F7FC0095102FE80EF91E0A1F1B1F30E06B
:102E200081EF9FEF289FB001299F700D389F700D93
:102E30001124640F751F80E090E029E130E040E04C
:102E400050E00E948340E60EF71E081F191FE09213
:102E5000A204F092A3040093A4041093A50480910B
:102E60008E048E5F80938E0480918E04803108F4EE
:102E700029CEE090AA04F090AB040091AC0410912C
:102E8000AD046091A2047091A3048091A404909178
:102E9000A5046C5F7F4F8F4F9F4FA8019701220FB2
:102EA000331F441F551F220F331F441F551F220F6E
:102EB000331F441F551F2E193F09400B510B620F42
:102EC000731F841F951F28E030E040E050E00E940F
:102ED000F740C901DA018093AA049093AB04A09350
:102EE000AC04B093AD041092A2041092A30410920B
:102EF000A4041092A50410928E04E4CD80910B01DD
:102F000090910C01281B390B30938D0420938C0475
:102F1000D9CD27B580911301682F70E0660F771F18
:102F2000660F771F709561957F4F8EED94E00E943C
:102F3000C240620F711D603171050CF45BC087B532
:102F400090E0861B970B9093300180932F0167BD13
:102F500024CF20323105D4F58EE490E0D901A89F2A
:102F60009001A99F300DB89F300D1124245C394089
:102F70001BCD809113012091A6043091A70460EF2E
:102F8000869FC00111248217930708F041C0E0908A
:102F90001301209113014091A6045091A704809140
:102FA000A2049091A304A091A404B091A504E69E6C
:102FB000700111240027F7FC0095102FE80EF91E70
:102FC0000A1F1B1F30E080E19FEF2CCFBFE02D3D9B
:102FD0003B070CF4E9CC2C5D3F408EE490E0F90116
:102FE000E89F9001E99F300DF89F300D1124245285
:102FF000304FDACC87B5882309F4CFCE87B581501E
:1030000087BD81E090E09093300180932F01C5CE81
:1030100080918E048F3049F18091A6049091A7048D
:103020002091A2043091A3044091A4045091A504DE
:10303000A0E0B0E0820F931FA41FB51F8093A204ED
:103040009093A304A093A404B093A50408CF87B5DC
:103050008E3F08F0A2CE87B58F5F87BD81E090E0FC
:103060009093300180932F0198CE8091A604909187
:10307000A7042091A2043091A3044091A40450918C
:10308000A50496958795A0E0B0E0820F931FA41F3A
:10309000B51F8093A2049093A304A093A404B093BB
:1030A000A504DDCEEF92FF920F931F93DF93CF9392
:1030B000CDB7DEB72C970FB6F894DEBF0FBECDBFED
:1030C0007E010894E11CF11CD701E7E1F1E08CE0FE
:1030D00001900D928150E1F710E08AE090E00E94AB
:1030E00018132091820430918304442737FD4095C2
:1030F000542F89819A81AB81BC81820F931FA41FB9
:10310000B51F89839A83AB83BC832091840430915B
:103110008504442737FD4095542F8D819E81AF81D2
:10312000B885820F931FA41FB51F8D839E83AF8325
:10313000B8872091860430918704442737FD409555
:10314000542F89859A85AB85BC85820F931FA41F58
:10315000B51F89879A87AB87BC871F5F1A3009F034
:10316000BCCF00E010E0F701608171818281938122
:103170006B5F7F4F8F4F9F4F2AE030E040E050E081
:103180000E94F740D801AA0FBB1FFD01E35FFE4F6D
:1031900040815181F801EA5DFD4F8081882319F05B
:1031A000309521953F4F240F351FA35FBE4F1196D9
:1031B0003C932E930F5F1F4F84E090E0E80EF91EC2
:1031C0000330110581F660910D0170910E010E948E
:1031D000863760910F017091100186E090E00E94A7
:1031E0008637609111017091120188E090E00E9491
:1031F00086371092960410929504809195049091D0
:103200009604909394048093930484E690E00E9443
:1032100018132C960FB6F894DEBF0FBECDBFCF911A
:10322000DF911F910F91FF90EF900895CF92DF9261
:10323000EF92FF920F931F93DF93CF93CDB7DEB73B
:103240002C970FB6F894DEBF0FBECDBF7E01089459
:10325000E11CF11CD701E3E2F1E08CE001900D925A
:103260008150E1F74091C301842F83708F5F809379
:10327000A904242F30E0C9018C7090709595879532
:10328000959587958F5F8093AE0420733070359548
:1032900027953595279535952795359527952F5F52
:1032A0002093A80442954695469543704F5F4093FE
:1032B0009D040E94D13F10E084E190E00E94181329
:1032C0002091970430919804442737FD4095542F5E
:1032D00089819A81AB81BC81820F931FA41FB51F86
:1032E00089839A83AB83BC832091990430919A049B
:1032F000442737FD4095542F8D819E81AF81B8853D
:10330000820F931FA41FB51F8D839E83AF83B88741
:1033100020919B0430919C04442737FD4095542F05
:1033200089859A85AB85BC85820F931FA41FB51F25
:1033300089879A87AB87BC871F5F103209F0BCCFA3
:10334000670120EDE22E23E0F22E00E010E0F6010E
:1033500061917191819191916F01605F7F4F8F4F6A
:103360009F4F20E230E040E050E00E94F740F8013B
:10337000EE0FFF1FE95FFE4F318320838081918133
:10338000F701819391937F010F5F1F4F0330110568
:10339000F1F610928B0410928A0480918A04909125
:1033A0008B04909389048093880484E090E00E94C9
:1033B000DF3790930E0180930D0186E090E00E942C
:1033C000DF379093100180930F0188E090E00E9416
:1033D000DF37909312018093110184E690E00E9400
:1033E00018132C960FB6F894DEBF0FBECDBFCF9149
:1033F000DF911F910F91FF90EF90DF90CF90089594
:10340000E3E3F1E080E2819391E0E338F907D9F753
:103410000895FF920F931F938091760290E080FFB2
:1034200008C020917502222309F40DC12150209378
:1034300075023091320181FF08C020917502231777
:1034400009F406C12F5F2093750283709070039773
:1034500011F410927502E3E3F1E080E2819321E040
:10346000E338F207D9F720917502321718F4309338
:103470007502232F2A30C8F581E18093770200D0AE
:1034800000D00F92EDB7FEB7319681E0ADB7BEB771
:1034900011968C938CE796E0928381832383148228
:1034A0000E94890F0F900F900F900F900F908091B6
:1034B0007502873009F430C3883040F18B3009F44D
:1034C000F8C38C3008F0C7C0883009F4E2C48930F2
:1034D00009F460C4815080933201109275021092F9
:1034E00076021F910F91FF90089580E180937702FB
:1034F00000D000D00F92EDB7FEB7319681E0ADB7A6
:10350000BEB711968C9387E796E0C6CF823009F458
:1035100083C2833008F050C18823E1F6109277020D
:1035200000D00F9211E0EDB7FEB7118387E696E069
:10353000938382830E94890F84E180937702209194
:10354000DC018DB79EB70A970FB6F8949EBF0FBEE9
:103550008DBFEDB7FEB73196ADB7BEB711961C93D0
:1035600082E596E092838183822F6AE00E94A240E6
:1035700083831482822F0E94A24095831682108634
:1035800017828AE490E09287818785EC90E09487A7
:1035900083870E94890F88E280937702EDB7FEB798
:1035A0003D960FB6F894FEBF0FBEEDBF0E941A37CE
:1035B0002DB73EB7275030400FB6F8943EBF0FBE30
:1035C0002DBFEDB7FEB73196ADB7BEB711961C93C0
:1035D00023E436E0328321838383148288EC95E0F0
:1035E000968385830E94890F809183019091840145
:1035F000EDB7FEB737960FB6F894FEBF0FBEEDBF1E
:10360000069708F4BDC420918F02222309F4A6C4B2
:103610008CE38093770200D000D00F92EDB7FEB715
:103620003196ADB7BEB711961C9383E296E09283B4
:103630008183238314820E94890F0F900F900F9033
:103640000F900F904CCF3091320130937502F3CE32
:1036500010927502FACE8C3009F45DC18D3009F0FC
:1036600039CF1092770200D00F9211E0ADB7BEB7FC
:1036700011961C9311978AE194E013969C938E9374
:1036800012970E94890F84E180937702EDB7FEB70D
:1036900038970FB6F894FEBF0FBEEDBF3196ADB7A9
:1036A000BEB711961C9386E094E09283818380914B
:1036B000D50490E08D96948383838091DA0490E022
:1036C0008D96968385838091DF0490E08D96908718
:1036D00087838091E40490E08D96928781870E9491
:1036E000890F88E280937702EDB7FEB73196ADB7C8
:1036F000BEB711961C9382EF93E0928381838091F1
:10370000E90490E08D96948383838091EE0490E0A9
:103710008D96968385838091F30490E08D969087B3
:1037200087838091F80490E08D96928781870E942C
:10373000890F8CE380937702EDB7FEB736960FB60C
:10374000F894FEBF0FBEEDBF3196ADB7BEB7119670
:103750001C9381EE93E0928381838091FD0490E03D
:103760008D96948383830E94890F0F900F900F9002
:103770000F900F9080910205882309F02EC480914C
:103780000705882309F012C480910C05882309F4E9
:10379000A6CE88E48093770200D00F9281E0EDB747
:1037A000FEB7818388ED93E0938382830E94890F23
:1037B0000F900F900F9093CE833009F4FBC18430AB
:1037C00009F088CE10927702E0916A05F0E0EE0FE2
:1037D000FF1FE85EFA4F40815181E0916B05F0E0F8
:1037E000EE0FFF1FE85EFA4F208131818DB79EB743
:1037F00007970FB6F8949EBF0FBE8DBFEDB7FEB70B
:10380000319611E0ADB7BEB711961C938DE895E0E7
:103810009283818354834383368325830E94890F57
:1038200084E180937702E0916C05F0E0EE0FFF1FDA
:10383000E85EFA4F40815181E0916D05F0E0EE0FB6
:10384000FF1FE85EFA4F20813181EDB7FEB7319658
:10385000ADB7BEB711961C938DE795E09283818337
:1038600054834383368325830E94890F88E28093A3
:103870007702E0916E05F0E0EE0FFF1FE85EFA4F71
:1038800040815181E0916F05F0E0EE0FFF1FE85E8F
:10389000FA4F20813181EDB7FEB73196ADB7BEB793
:1038A00011961C938DE695E0928381835483438324
:1038B000368325830E94890F8CE380937702E09101
:1038C0007005F0E0EE0FFF1FE85EFA4F4081518176
:1038D000E0917105F0E0EE0FFF1FE85EFA4F2081E6
:1038E0003181EDB7FEB73196ADB7BEB711961C93D7
:1038F0008DE595E0928381835483438336832583CA
:103900000E94890FEDB7FEB737960FB6F894FEBF49
:103910000FBEEDBFE4CD1092770200D00F9211E000
:10392000ADB7BEB711961C93119788E694E0139635
:103930009C938E9312970E94890F84E18093770263
:10394000EDB7FEB738970FB6F894FEBF0FBEEDBFC8
:103950003196ADB7BEB711961C9383E594E0928380
:1039600081838091D604838314828091DB048583D4
:1039700016828091E004878310868091E504818718
:1039800012860E94890F88E280937702EDB7FEB716
:103990003196ADB7BEB711961C938EE394E0928337
:1039A00081838091EA04838314828091EF0485836C
:1039B00016828091F404878310868091F9048187B0
:1039C00012860E94890F8CE380937702EDB7FEB7D1
:1039D0003196ADB7BEB711961C9389E294E09283FD
:1039E00081838091FE048383148280910305858303
:1039F0001682809108058783108680910D05818746
:103A000012860E94890FEDB7FEB73B960FB6F89469
:103A1000FEBF0FBEEDBF63CD1092770200D00F92B4
:103A2000FF24F394ADB7BEB71196FC9211978AE0CC
:103A300096E013969C938E9312970E94890F84E1CF
:103A40008093770200D000D00DB71EB70F5F1F4FD5
:103A5000EDB7FEB7F1828BEF95E0D80112969C93FB
:103A60008E93119760914E0570914F05809150058E
:103A70009091510524E736E040E050E00E94F74085
:103A8000F80123833483458356830E94890F88E29B
:103A9000809377020DB71EB70F5F1F4FADB7BEB74C
:103AA0001196FC928CEE95E0F801928381836091EF
:103AB000520570915305809154059091550524E766
:103AC00036E040E050E00E94F740D80113962D9375
:103AD0003D934D935C9316970E94890F8CE38093DE
:103AE00077020F900F90EDB7FEB73196ADB7BEB726
:103AF0001196FC928DED95E09283818380918701F0
:103B000090918801948383830E94890F0F900F9076
:103B10000F900F900F90E3CC84E180937702809117
:103B200014019091150100911401109115012DB708
:103B30003EB7275030400FB6F8943EBF0FBE2DBFA2
:103B4000EDB7FEB73196FF24F394ADB7BEB711962B
:103B5000FC922AE435E0328321836AE070E00E941F
:103B6000C24074836383C8016AE070E00E94C2406F
:103B7000968385830E94890F88E280937702209143
:103B80009202309193020F900F90EDB7FEB73196ED
:103B9000ADB7BEB71196FC928CE395E0928381831A
:103BA000348323830E94890F0F900F900F900F9002
:103BB0000F9095CC1092770220911A0530911B0539
:103BC00040911C0550911D05EDB7FEB737970FB614
:103BD000F894FEBF0FBEEDBF319611E0ADB7BEB792
:103BE00011961C938DEC95E092838183348323831B
:103BF000568345830E94890F84E180937702209148
:103C00001E0530911F054091200550912105EDB70B
:103C1000FEB73196ADB7BEB711961C938DEB95E00C
:103C20009283818334832383568345830E94890F43
:103C300088E28093770220912205309123054091FC
:103C4000240550912505EDB7FEB73196ADB7BEB747
:103C500011961C938DEA95E09283818334832383AC
:103C6000568345830E94890F8CE3809377022091CD
:103C70002605309127054091280550912905EDB77B
:103C8000FEB73196ADB7BEB711961C938DE995E09E
:103C90009283818334832383568345830E94890FD3
:103CA000EDB7FEB737960FB6F894FEBF0FBEEDBF67
:103CB00016CC1092770200D00F9211E0ADB7BEB7CC
:103CC00011961C93119788EA94E013969C938E9317
:103CD00012970E94890F84E18093770200D000D070
:103CE000EDB7FEB73196ADB7BEB711961C9388E914
:103CF00094E0928381838091BB04992787FD9095FE
:103D0000948383838091BC04992787FD9095968343
:103D100085830E94890F88E280937702EDB7FEB712
:103D20003196ADB7BEB711961C9388E894E09283A4
:103D300081838091BE04838314828091BD0499277E
:103D400087FD9095968385830E94890F8CE38093ED
:103D50007702EDB7FEB73196ADB7BEB711961C939B
:103D600088E794E0928381838091BF04992787FD3F
:103D70009095948383838091C204858316820E94E8
:103D8000890FEDB7FEB737960FB6F894FEBF0FBE9A
:103D9000EDBFA5CB10927702EDB7FEB737970FB600
:103DA000F894FEBF0FBEEDBF319611E0ADB7BEB7C0
:103DB00011961C938EEE94E0928381838091DD02B4
:103DC0009091DE02948383838091E5029091E602D4
:103DD000968385830E94890F84E180937702EDB7F3
:103DE000FEB73196ADB7BEB711961C938CED94E03B
:103DF000928381838091DF029091E0029483838398
:103E00008091E7029091E802968385830E94890F52
:103E100088E280937702EDB7FEB73196ADB7BEB7B3
:103E200011961C938AEC94E0928381838091E10245
:103E30009091E202948383838091E9029091EA0257
:103E4000968385830E94890F8CE380937702EDB778
:103E5000FEB73196ADB7BEB711961C9388EB94E0D0
:103E6000928381838091E3029091E402948383831F
:103E70008091EB029091EC02968385830E94890FDA
:103E8000EDB7FEB737960FB6F894FEBF0FBEEDBF85
:103E900026CB1092770200D00F9211E0EDB7FEB75B
:103EA00011838DE295E0938382830E94890F84E1E0
:103EB0008093770200D0EDB7FEB73196ADB7BEB7AD
:103EC00011961C938EE195E0928381838091890104
:103ED00090918A01948383830E94890F88E2809362
:103EE0007702EDB7FEB73196ADB7BEB711961C930A
:103EF0008FE095E092838183809187019091880182
:103F0000948383830E94890F8CE380937702EDB7BB
:103F1000FEB73196ADB7BEB711961C9380E095E021
:103F2000928381838091870190918801845E9D4F67
:103F30002091890130918A01821B930B68E671E020
:103F40000E94C240845B9040948383830E94890FC7
:103F50000F900F900F900F900F90C1CA8CE3809339
:103F6000770200D00F92EDB7FEB7118383E196E0A0
:103F7000938382830E94890F0F900F900F90AFCA96
:103F80008CE38093770200D00F92ADB7BEB7119645
:103F90001C93119786E396E013969C938E93129749
:103FA0000E94890F0F900F900F9099CA84E480931C
:103FB000770200D00F9281E0ADB7BEB711968C9317
:103FC00011978BED93E013969C938E9312970E941A
:103FD000890F0F900F900F90D7CB80E480937702DA
:103FE00000D00F92EDB7FEB711838EED93E093836F
:103FF00082830E94890F0F900F900F90C0CB87B1E2
:104000008C6087B9429A439A1092B6041092B50414
:1040100080E88093B4048093B3040895382F6B3FF5
:1040200020F0273E20F52A3078F1A32FB0E0FD01E3
:10403000EB54FB4F8081815080838F5FB9F46150D6
:104040006083FD01ED54FB4F80818130B9F186958D
:1040500080838081842331F528B184E090E002C020
:10406000880F991FAA95E2F7282B28B9089547FDD4
:104070000DC028B184E090E002C0880F991F3A95E6
:10408000E2F7282B28B9089547FDF3CF28B184E043
:1040900090E002C0880F991F3A95E2F7809582233D
:1040A00088B9089528B184E090E002C0880F991F74
:1040B000AA95E2F78095822388B9089580E88083E5
:1040C000C8CF809178028150809378028F5F09F089
:1040D000089584E08093780280E06091A10540918A
:1040E000A0052091CE010E940E2081E06091A305E1
:1040F0004091A2052091CF010E940E200895809149
:10410000A60386FF07C042988091A70386FD07C0DB
:10411000439A0895429A8091A70386FFF9CF439866
:1041200008958091B7040895809186020895809142
:10413000870208950E94602908951F930E944828CD
:10414000182F0E946E22811708F4812F1F91089565
:104150001F93CF93DF93CDEDD2E010E00BC02F3F44
:10416000310594F42F5F3F4F398328831F5F2296D8
:104170001830C1F0812F0E94282897FD17C0288190
:104180003981281739075CF3121613067CF782175A
:10419000930764F721503040398328831F5F2296AC
:1041A000183041F7DF91CF911F91089580E090E0A2
:1041B000E6CFEF92FF920F931F93CF93DF930E946E
:1041C0001B270E9421220E94BB390E9425287C01C6
:1041D0000E9415228C01FC0180819181F7012081D0
:1041E0003181820F931F90937E0280937D02F801AC
:1041F00082819381F70122813381820F931F9093F3
:10420000800280937F02F80184819581F7012481E7
:104210003581820F931F0E94D93E0E94913A90935C
:10422000840280938302F80186819781F7012681B9
:104230003781820F931F9093820280938102809135
:104240007D0290917E029093C1038093C003809180
:104250007F02909180029093C3038093C2030E94D7
:104260009D20843008F08EC010928502EDE7F2E0C8
:10427000A9E7B2E0C4E6D0E0608171814D915C9124
:104280001197CB019C0197FD7AC0359527953595FF
:10429000279537FD70C04217530708F03FC09B01B8
:1042A00077FD92C0C901959587959595879511964B
:1042B0009C938E938536910518F01196DC93CE93DE
:1042C0003296129682E0E138F807B1F60E9448284B
:1042D000833008F075C000E00E946E22833008F041
:1042E0005CC090E0002309F05EC0992301F51092B4
:1042F0008702109286028091A6038F7E8093A60388
:10430000002369F58091A7038F7E8093A703DF9137
:10431000CF911F910F91FF90EF9008954115510596
:1043200079F24150504011965C934E93C9CF109250
:10433000870280918602981709F44AC090938602FA
:104340000E9418228093B70480918702882399F2F3
:104350008091A60380618093A603002399F2809147
:10436000A70380618093A703DF91CF911F910F91E5
:10437000FF90EF900895309521953F4F8CCF2D5FA2
:104380003F4F83CF0E94A8200E94953B80918502D9
:104390000E94C9288093850269CF0E941B22982F12
:1043A000002309F4A2CF1092870280918602081799
:1043B00099F0009386020E946F288093B704C4CFBF
:1043C0000E946628082F88CF309521953F4F6ACFED
:1043D00081E080938702B2CF81E080938702E9CFAA
:1043E0001F93CF93DF93CDEDD2E010E0812F0E9499
:1043F0002828899399931F5F1830C1F7DF91CF91D7
:104400001F9108950E9407220E94863908951092F4
:10441000C2041092BB041092BC041092BD0410920E
:10442000BE0485E58093B804089584EC94E0089573
:104430008091C20408958091C004089580E090E0C6
:1044400008958091C304882389F41092CB041092BC
:10445000CA041092C9041092C8041092C7041092A2
:10446000C6041092C5041092C4040895815080932C
:10447000C3042091790530E08091BB04992787FD22
:104480009095AC01249FC001259F900D349F900D05
:1044900011249093C5048093C4048091BC0499278F
:1044A00087FD9095AC01429FC001439F900D529FA4
:1044B000900D11249093C7048093C6048091BE048C
:1044C0008093C8041092C9048091BD04992787FD88
:1044D00090959093CB048093CA0408958091C3046F
:1044E000813580F4882359F48091C20480FF0DC087
:1044F00090E08091CD01813818F091E001C093E007
:10450000892F089594E0892F089590E0892F0895C8
:104510001092CD041092CC041092CF041092CE04CD
:104520000895EF92FF920F931F9324E736E040E047
:1045300050E00E94F740CA01B90128E631E040E0AE
:1045400050E00E94F740AC01CB01DA019C01AD01C3
:1045500057FD25C061E02A3531054105510564F05C
:1045600084EB90E0A0E0B0E07C018D01E21AF30A58
:10457000040B150BA8019701E22FF0E0EE0FFF1FCF
:10458000EF57F94F25913491613019F0309521950D
:104590003F4FC9011F910F91FF90EF9008955095E3
:1045A0004095309521953F4F4F4F5F4F6FEFD3CFE1
:1045B000693C24E4720722E0820720E092073CF481
:1045C00068537B4B8D4F9F4F0E94912208956855F1
:1045D0007E4C864090400E949122089524E736E068
:1045E00040E050E00E94F740C901DA019C01AD01B2
:1045F0008A359105A105B105B4F024EB30E040E027
:1046000050E0281B390B4A0B5B0BE22FF0E0EE0F5A
:10461000FF1FE95CF84F8591949122273327281BCF
:10462000390BC9010895263A6FEF36076FEF460739
:104630006FEF560774F42C543F4F4F4F5F4FE22FEC
:10464000F0E0EE0FFF1FE95CF84F25913491C901AE
:104650000895B7FFF4CF22273327A901281B390B70
:104660004A0B5B0BD2CF9FB7F8943998389A88B130
:10467000836088B98091B9008C7F8093B9008AE209
:104680008093B80010928B0210928D0210928E02CD
:10469000E4EDF4E01082118212821482359685E0F6
:1046A000E031F807B9F79FBF089580938B0285EA40
:1046B0008093BC00089580938B0284E98093BC00B2
:1046C00008958093BB0085E88093BC00089585EC35
:1046D0008093BC00089585E88093BC0008950F93F3
:1046E0001F9310928B020CEB10E084E9D8018C939D
:1046F00010928B02EBEBF0E0808180938D021092A0
:104700008D0210928E0280E88C931092BD00109260
:10471000BA0010821092B9001092B8000E943323A0
:1047200010928B0285EAF80180831F910F91089502
:104730001F920F920FB60F9211242F938F939F9376
:10474000EF93FF9380918B028F5F80938B02815058
:10475000853009F4C3C0863020F1893009F497C050
:104760008A30E0F5873009F411C1883009F404C1BA
:1047700010928B0284E98093BC008AE090E09093D1
:1047800084018093830110928D0210928E02FF911A
:10479000EF919F918F912F910F900FBE0F901F90CF
:1047A0001895823009F47FC0833080F1833009F49A
:1047B000BCC08430E9F680918E022091BB0090E06D
:1047C000FC01EE0FFF1FEE0FFF1FE80FF91FEC5269
:1047D000FB4F238385E88093BC00D9CF8A3009F44E
:1047E0009DC08B3029F610928B0284E98093BC0027
:1047F0008AE090E0909384018093830180919002FD
:10480000823008F417C110929002C1CF8823F9F0CA
:10481000813009F0ADCF80918D0290E0FC01EE0F68
:10482000FF1FEE0FFF1FE80FF91FEC52FB4F8081B7
:104830008093BB0085E88093BC00A9CF80918D0256
:104840008C3088F480918D028F5F80938D02E0918F
:104850008D02F0E0EE0FFF1FEE0FFF1FE953FA4F3E
:10486000858518165CF780918D028C3008F495C010
:1048700010928D0283E080938B0280918E02880FCC
:104880008D5A8093BB0085E88093BC0080CFE09177
:104890009002F0E0E053FB4F80818093BB0085E8FD
:1048A0008093BC0074CF8091B900803309F484C038
:1048B00010928B0284E98093BC008AE090E0909390
:1048C00084018093830180918D028F5F80938D029C
:1048D00010928B0285EA8093BC0059CF80918E02A2
:1048E0002091BB0090E0FC01EE0FFF1FEE0FFF1FB9
:1048F000E80FF91FEC52FB4F248380918E028F5FEB
:1049000080938E0280918E028C3010F010928E0275
:1049100010928B0284E98093BC0039CF80E88093A9
:10492000BB0085E88093BC0032CF8091B900803411
:1049300009F46CC080918E0290E0FC01EE0FFF1F25
:10494000EE0FFF1FE80FF91FEC52FB4F1182809111
:104950008E028F5F80938E0280918E028C3048F59C
:1049600010928B0284E98093BC0080919102809325
:104970008F02109291020BCF80919002880F805F7E
:104980008093BB0085E88093BC0001CF88E98093C9
:10499000BB0085E88093BC00FACE80918D0290E048
:1049A0008996880F991F8093BB0085E88093BC008F
:1049B000EECE10928E02D4CF80919102882329F4FA
:1049C00080918D028F5F8093910280918D0290E0A3
:1049D000FC01EE0FFF1FEE0FFF1FE80FF91FEC5257
:1049E000FB4F82818F5F8283882309F061CF8091A2
:1049F0008D0290E0FC01EE0FFF1FEE0FFF1FE80F8E
:104A0000F91FEC52FB4F8FEF828352CF80918E02C1
:104A100020918E0290E0FC01EE0FFF1FEE0FFF1FB2
:104A2000E80FF91FEC52FB4F2C5F218385EC80933C
:104A3000BC009BCF8F5F8093900287E080938B02B6
:104A400085EA8093BC00A3CE8F929F92BF92CF92B3
:104A5000DF92EF92FF920F931F93CF93DF9300D0DB
:104A60000F92ADB7BEB711961C9211978FE098E0E8
:104A700013969C938E9312970E94890FE4EDF4E0B5
:104A80000F900F900F9010823596B5E0E031FB0744
:104A9000D1F710928B0285EA8093BC0080E197E207
:104AA0000197F1F710928E028F010B531040E8012D
:104AB00061E0E62EF12C55EAB52E40E1C42E47E226
:104AC000D42E3BE0832E38E0932E08C02596089420
:104AD000E11CF11CB5E0C131DB0739F110928B020A
:104AE000B092BC00C6010197F1F78881882371F369
:104AF00000D000D00F92EDB7FEB73196ADB7BEB77C
:104B000011961C9292828182F482E3820E94890F24
:104B10000F900F900F900F900F9025960894E11C26
:104B2000F11CB5E0C131DB07C9F6C4EDD5E021E0E9
:104B3000E22EF12C9DEEC92E97E0D92EF80180814E
:104B40008823C1F488811816ACF400D000D00F92ED
:104B5000EDB7FEB73196ADB7BEB711961C92D282B3
:104B6000C182F482E3820E94890F0F900F900F9010
:104B70000F900F90F80111820B5F1F4F249608943D
:104B8000E11CF11CF5E001311F07C1F6DF91CF9167
:104B90001F910F91FF90EF90DF90CF90BF909F906B
:104BA0008F9008959FB7F89456985E9A8AB188635B
:104BB0008AB98BB1877C8BB98091ED02813011F07D
:104BC000539A5B98809180008C70809380008091D4
:104BD0008100837E8093810080918100836C80932B
:104BE0008100809182008F738093820080916F009A
:104BF000887F80936F0080916F00806280936F0048
:104C000010929302109292029FBF08951F920F92EA
:104C10000FB60F9211240F931F932F933F934F932F
:104C20005F936F937F938F939F93AF93BF93CF9334
:104C3000DF93EF93FF93209186003091870080915E
:104C4000960290919702281B390B809186009091D3
:104C500087009093970280939602C9018D549440E7
:104C6000835F9A4118F58091980290919902049778
:104C700014F01092850181E090E090939902809366
:104C80009802FF91EF91DF91CF91BF91AF919F91EA
:104C90008F917F916F915F914F913F912F911F91D4
:104CA0000F910F900FBE0F901F901895C091980212
:104CB000D0919902C930D10524F7C9018B5F90408A
:104CC000845B914008F055C0265D31408E01000F95
:104CD000111FF801E85EFA4F80819181F901E81B0C
:104CE000F90BCF01F7FD60C006978CF4809192021A
:104CF00090919302883C91050CF04FC080919202F4
:104D0000909193020A969093930280939202F801F5
:104D1000E85EFA4F8081918101972817390734F0B6
:104D2000808191810196821793077CF58091920290
:104D300090919302833C910514F1F801E85EFA4FDB
:104D400080819181A901481B590BCA0163E070E081
:104D50000E94C240CB01880F991F860F971FF80150
:104D6000E45DFA4F91838083085E1A4FF801318326
:104D700020832196D0939902C093980282CFF801A4
:104D8000E45DFA4F11821082EFCF2F5F3F4F233047
:104D9000310570F420E030E0C9CF88EC90E09093CA
:104DA000930280939202B3CF909581959F4F9CCFB1
:104DB00020813181BBCF80916C05E82FF0E0EE0FB0
:104DC000FF1FE85EFA4F8081918186359105C4F01E
:104DD00080916D05E82FF0E0EE0FFF1FE85EFA4FBF
:104DE00080819181863591053CF4808191818B5A37
:104DF0009F4F24F484E0089582E0089580E00895B0
:104E0000808191818B5A9F4FCCF780916D05E82F5F
:104E1000F0E0EE0FFF1FE85EFA4F8081918186354A
:104E200091053CF4808191818B5A9F4F3CF786E03D
:104E3000089588E008951F93CF93DF9380919202A5
:104E400090919302892B09F4D7C08091920290919E
:104E5000930201979093930280939202809185012F
:104E60008150809385018F5F09F0B7C0E0916A059A
:104E7000F0E0EE0FFF1FDF01A85EBA4F2D913C91CD
:104E80006091790570E0E45DFA4F808191814091F5
:104E90007A0550E0FC01E49FC001E59F900DF49F6E
:104EA000900D1124F901E69F9001E79F300DF69FC8
:104EB000300D1124820F931F9093110580931005DC
:104EC000E0916B05F0E0EE0FFF1FDF01A85EBA4F27
:104ED0002D913C91E45DFA4F80819181FC01E49F2A
:104EE000C001E59F900DF49F900D1124A901469FEC
:104EF0009001479F300D569F300D1124820F931F54
:104F00009093130580931205E0916C05F0E0EE0F8D
:104F1000FF1FDF01A85EBA4F2D913C91E45DFA4F6F
:104F20004081518128583F4F8091C20190E0BC01DF
:104F3000469FC001479F900D569F900D1124280F4A
:104F4000391F309315052093140537FD71C0E0918A
:104F50006D05F0E0EE0FFF1FDF01A85EBA4F2D9147
:104F60003C91E45DFA4F80819181CC27DD27C21B03
:104F7000D30BC81BD90B10917B05BE01882777FD89
:104F80008095982F212F30E040E050E00E94834030
:104F9000FE01D7FD55C09F01442737FD4095542F92
:104FA0000E94834020E032E040E050E00E94F74061
:104FB000812F90E0C89FB001C99F700DD89F700DE0
:104FC000112477FD3AC07595679575956795260FFD
:104FD000371F30931705209316050E94DB26982F64
:104FE000809194029817E1F09093940210929502A8
:104FF000DF91CF911F910895109217051092160519
:1050000010921505109214051092130510921205B6
:105010001092110510921005DF91CF911F91089504
:1050200080919502883CC0F78F5F80939502F4CF02
:1050300010921505109214058ACF6D5F7F4FC3CF74
:10504000EE27FF27EC1BFD0BA6CF80E195E008952E
:10505000843068F0E82FF0E0EE0FFF1FE65EFA4FB5
:105060000190F081E02DED58FF4FCF010895E82F1A
:10507000F0E0E659FA4FE481F0E0EE0FFF1FE85E42
:10508000FA4F0190F081E02DED58FF4FCF010895C8
:105090008091920290919302803A910594F48091CC
:1050A0009202909193028C3891054CF48091920277
:1050B000909193028837910534F481E0089583E05C
:1050C000089584E0089582E00895089580919502FE
:1050D000883C11F080E008958091940208958091B9
:1050E0006A05E82FF0E0EE0FFF1FE85EFA4F8081BF
:1050F000918187349105B4F080916B05E82FF0E041
:10510000EE0FFF1FE85EFA4F808191818734910591
:105110003CF4808191818A5B9F4FFCF083E008958D
:1051200082E00895808191818A5B9F4FC4F48091D1
:105130006B05E82FF0E0EE0FFF1FE85EFA4F80816D
:105140009181873491053CF4808191818A5B9F4FE6
:10515000E4F087E0089588E0089584E00895809160
:105160006B05E82FF0E0EE0FFF1FE85EFA4F80813D
:105170009181873491055CF4808191818A5B9F4F96
:1051800014F080E0089585E0089586E0089581E0B8
:105190000895CF93DF93682F80916B05A82FB0E01F
:1051A000AA0FBB1FFD01E85EFA4F2081318180917B
:1051B0009205482F50E04217530724F48091B5051B
:1051C00082FD75C062FD61C0FD01E85EFA4F80811D
:1051D0009181CC27DD27C41BD50B8C179D0724F4A8
:1051E0008091B50583FD61C063FD40C080916A0573
:1051F000A82FB0E0AA0FBB1FFD01E85EFA4F808127
:1052000091814817590724F48091B50580FD51C05C
:1052100060FD1EC0FD01E85EFA4F808191818C1710
:105220009D0724F48091B50581FD45C061FF0CC048
:10523000A85EBA4F2D913C9180919305C81BD1096E
:10524000C217D3070CF46D7E862FDF91CF9108959E
:10525000FD01E85EFA4F2081318180919305481B62
:10526000510924173507B4F66E7ED4CFA85EBA4F25
:105270002D913C9180919305FE01E81BF109E21705
:10528000F3070CF0B3CF677DB1CFFD01E85EFA4FB5
:105290002081318180919305FA01E81BF1092E17D5
:1052A0003F070CF091CF6B7D8FCF68629FCF646218
:1052B0008BCF6161AFCF6261862FDF91CF9108956F
:1052C00080916A05A82FB0E0AA0FBB1FFD01E85E20
:1052D000FA4F808191818D5E9F4F14F0109286016C
:1052E000A85EBA4F8D919C918A5B9F4F44F4809148
:1052F0008601882321F481E080938601089580E06F
:105300000895E82FF0E0EE0FFF1FE25AFD4F608195
:105310007181882777FD8095982F2CEE30E040E052
:1053200050E00E948340089560915E0270915F0298
:10533000882777FD8095982F2CEE30E040E050E0F4
:105340000E94834060934E0570934F0580935005F3
:10535000909351056091600270916102882777FDFA
:105360008095982F0E948340609352057093530557
:10537000809354059093550508958091AF049091C2
:10538000B0042091A8023091A902820F931F63E01C
:1053900070E00E94C2407093430560934205809183
:1053A0009E0490919F04820F931F63E070E00E941F
:1053B000C24070935B0560935A0580918F04909171
:1053C00090049093570580935605809182049091A4
:1053D00083042091A2023091A302820F931F909325
:1053E000A3028093A2028091B1049091B204209113
:1053F000AA023091AB02820F931F63E070E00E941B
:10540000C24070934505609344058091A00490913B
:10541000A104820F931F63E070E00E94C24070936A
:105420005D0560935C058091910490919204909346
:1054300059058093580580918404909185042091AA
:10544000A4023091A502820F931F9093A50280932E
:10545000A4028091A6029091A70201969093A702C0
:105460008093A60220918C0430918D048091AC022F
:105470009091AD02820F931F909349058093480548
:1054800010921601EAE7F0E08081886C808308952D
:105490002F923F924F925F926F927F928F929F9244
:1054A000AF92BF92CF92DF92EF92FF920F931F9332
:1054B000DF93CF9300D000D0CDB7DEB780918502C7
:1054C000882379F420918604309187048091C60165
:1054D000482F50E088279927841B950B28173907F8
:1054E000CCF58091A603877F8093A6038091A703C4
:1054F000877F8093A7031092BB031092BA03109288
:10550000BD031092BC031092C9031092C8031092FD
:10551000CB031092CA031092A1021092A002109223
:105520009F0210929E020F900F900F900F90CF91BC
:10553000DF911F910F91FF90EF90DF90CF90BF9080
:10554000AF909F908F907F906F905F904F903F9023
:105550002F900895809186049091870448175907E9
:105560000CF4BFCF8091A60388608093A60360915E
:105570007E058091810290918202805C9F4F8138EC
:10558000910508F0E5C021E08091790290917A02BE
:105590008134910540F480917B0290917C028134AA
:1055A000910508F4D8C066958091A703877F809302
:1055B000A703862F90E0A0E0B0E089839A83AB83B5
:1055C000BC8328EE622E23E0722E812C912C681A67
:1055D000790A8A0A9B0A60915E0270915F028827AD
:1055E00077FD8095982F2CEE30E040E050E00E944F
:1055F00083405B016C012AE030E040E050E00E9413
:10560000834024E736E040E050E00E94F7403093CA
:10561000BB032093BA0320904E0530904F05409075
:10562000500550905105C401B301A20191010E949F
:1056300083407B018C0169817A818B819C81A601E9
:1056400095010E948340E60EF71E081F191FC8012E
:10565000B70128EE33E040E050E00E94F740C90176
:10566000DA0180934E0590934F05A0935005B093B7
:1056700051058219930920919E0230919F02280FB3
:10568000391F30939F0220939E029093C903809309
:10569000C8036091600270916102882777FD809550
:1056A000982F2CEE30E040E050E00E9483405B01F8
:1056B0006C012AE030E040E050E00E94834024E7A3
:1056C00036E040E050E00E94F7403093BD03209365
:1056D000BC032090520530905305409054055090E3
:1056E0005505C401B301A20191010E9483407B01D1
:1056F0008C0169817A818B819C81A60195010E9430
:105700008340E60EF71E081F191FC801B70128EED7
:1057100033E040E050E00E94F740C901DA01809395
:10572000520590935305A0935405B09355058219E3
:1057300093092091A0023091A102280F391F3093C4
:10574000A1022093A0029093CB038093CA03EBCED7
:10575000669520E019CF222309F426CF8091A70374
:1057600088608093A70325CF9F92AF92BF92CF927C
:10577000DF92EF92FF920F931F93CF93DF9380916D
:105780008D0190918E01019790938E0180938D01F0
:10579000892B09F052C080E091E090938E018093B4
:1057A0008D019090990580919A05A82EBB24CC2458
:1057B000DD24CA18DB085EE9E52E52E0F52EC8EAC2
:1057C000D2E00CEC13E0F70120813181B901660FC2
:1057D000771F620F731F882777FD8095982F605879
:1057E0007F4F8F4F9F4F20E031E040E050E00E941C
:1057F000F740DA01C901692D70E00E94C2409B01A7
:1058000088819981860F971F998388838C159D05C0
:1058100004F5D982C882C601F80131832083958BB3
:10582000848BF701119211927F0122960E5F1F4F18
:10583000F2EAEF16F2E0FF0631F6DF91CF911F9109
:105840000F91FF90EF90DF90CF90BF90AF909F901F
:105850000895A816B90604F7B982A882C501DCCF5D
:10586000AF92BF92CF92DF92EF92FF920F931F936E
:10587000CF93DF9380919D02882321F080918A024B
:1058800080FF76C160914E0570914F058091500563
:105890009091510520E032E040E050E00E94F74056
:1058A000E90137FD7DC160915205709153058091EA
:1058B00054059091550520E032E040E050E00E9410
:1058C000F740690137FD70C1CC16DD060CF4D6C077
:1058D000209187013091880137FD0AC080914805E9
:1058E0009091490597FD54C1813891050CF4FEC093
:1058F00060E070E0C0E0D0E080918B0190918C017D
:10590000892B09F4BDC0B6017595679575956795A6
:10591000759567956F5F7F4FCE010E94C2409B01D6
:10592000442737FD4095542F80914A0590914B05AF
:10593000A0914C05B0914D05280F391F4A1F5B1FE0
:1059400020934A0530934B0540934C0550934D05E9
:105950008091B901C82FD0E0CC9EC001CD9E900DA2
:10596000DC9E900D112497FD24C195958795959502
:1059700087959595879595958795959587955E01DA
:10598000A81AB90AB7FCEDC080918B0190918C01E7
:10599000009709F0D6C0C0907B02D0907C02809125
:1059A000790290917A02C80ED91ED694C794D694E3
:1059B000C794D694C79480E490E0C80ED91E809115
:1059C000890190918A01AA2797FDA095BA2F7CE1C1
:1059D000E72E72E0F72E012D112DE81AF90A0A0BB5
:1059E0001B0BCA01B90126E832E040E050E00E94FA
:1059F000F740E20EF31E041F151FC801B70128E689
:105A000031E040E050E00E94F740645B70406A9DE6
:105A1000C0016B9D900D7A9D900D1124B6010E94DE
:105A2000C2409B01CE01880F991F8C0F9D1F8217CA
:105A300093070CF4ABC044275527481B590BB901F9
:105A4000241735070CF4BA019B01442737FD409514
:105A5000542F8091620590916305A0916405B091E7
:105A60006505820F931FA41FB51F80936205909355
:105A70006305A0936405B093650568C06E0128CFE7
:105A800089E1C816D1040CF03ECF80914005909179
:105A90004105860F971F90934105809340058091A3
:105AA0009C02882309F42FCF88EC90E00E945E3E90
:105AB0000091870110918801B801882777FD8095B2
:105AC000982F26E832E040E050E00E948340609347
:105AD0004A0570934B0580934C0590934D051093A8
:105AE0008A010093890110929C020DCF245E3D4FE4
:105AF00079010027F7FC0095102F60914A057091FD
:105B00004B0580914C0590914D052AE73DEF4FEFF5
:105B10005FEF0E94F740E20EF31E041F151FC8013D
:105B2000B70128E631E040E050E00E94F740645BB6
:105B30007040EB01CC0FDD1FCC0FDD1FCC0FDD1F44
:105B4000DBCE019790938C0180938B01DF91CF91F5
:105B50001F910F91FF90EF90DF90CF90BF90AF908B
:105B6000089584EF91E090938C0180938B01EECFA8
:105B70000E949A20882351F380919D028F5F809329
:105B80009D028530C0F40E94B73EE0CFBC015CCFDF
:105B9000909581959F4F813891050CF0A9CEA6CFA5
:105BA000D095C195DF4F7FCED094C194D108D394C6
:105BB0008BCE4F96DACE88EE93E00E945E3EC6CF43
:105BC0002F923F924F925F926F927F928F929F920D
:105BD000AF92BF92CF92DF92EF92FF920F931F93FB
:105BE000DF93CF93CDB7DEB72C970FB6F894DEBF17
:105BF0000FBECDBF60914E0570914F05809150054D
:105C0000909151050E94D8229A8389836091520510
:105C10007091530580915405909155050E94D822AA
:105C20006C016091520570915305809154059091DB
:105C300055050E9491228C0160914E0570914F058F
:105C400080915005909151050E94EE221C016090B8
:105C50005A0570905B05882477FC8094982CC601C7
:105C6000AA2797FDA095BA2F8F839887A987BA870F
:105C7000A0904805B0904905CC24B7FCC094DC2C1A
:105C8000C801AA2797FDA095BA2F8B839C83AD836B
:105C9000BE836F81788589859A85A40193010E94CE
:105CA00083407B018C016B817C818D819E81A6016B
:105CB00095010E948340E61AF70A080B190BC801E8
:105CC000B70120E030E140E050E00E94F74030931F
:105CD0005F0520935E05A0915C05B0915D05BC87D2
:105CE000AB87609152057091530580915405909156
:105CF00055050E94D822AA2797FDA095BA2FBC016E
:105D0000CD01A60195010E94834020E032E040E0F1
:105D100050E00E94F74079018A016B817C818D817E
:105D20009E81A40193010E94834020E032E040E084
:105D300050E00E94F740E20EF31E041F151F44249A
:105D400037FC4094542CC801B701A20191010E9474
:105D5000834020E030E840E050E00E94F740EB85CF
:105D6000FC85E20FF31FF0936105E09360058981E4
:105D70009A815C01CC24B7FCC094DC2C20914805AE
:105D800030914905442737FD4095542F6F81788520
:105D900089859A850E948340A60195010E94F7405B
:105DA00079018A0120915A0530915B05442737FD1E
:105DB0004095542F6B817C818D819E810E94834010
:105DC000A60195010E94F740E20EF31EF0924705EE
:105DD000E09246052C960FB6F894DEBF0FBECDBFFD
:105DE000CF91DF911F910F91FF90EF90DF90CF90B7
:105DF000BF90AF909F908F907F906F905F904F90EB
:105E00003F902F900895EF92FF920F931F938091F0
:105E10008502882321F48091720586FD13C180914B
:105E20005A0590915B0590935F0580935E05809184
:105E30005C0590915D05909361058093600560918C
:105E40004805709149057093470560934605809118
:105E50004605909147057C010027F7FC0095102F1F
:105E600080914A0590914B05A0914C05B0914D054C
:105E7000E80EF91E0A1F1B1FE0924A05F0924B051F
:105E800000934C0510934D059B01442737FD409529
:105E9000542F8091620590916305A0916405B091A3
:105EA0006505820F931FA41FB51F80936205909311
:105EB0006305A0936405B093650580E7E8168CE858
:105EC000F80683E0080780E018070CF482C080E938
:105ED00093E7ACEFBFEFE80EF91E0A1F1B1FE0921D
:105EE0004A05F0924B0500934C0510934D058091A7
:105EF0005E0590915F059C01442737FD4095542F26
:105F000080914E0590914F05A0915005B09151059B
:105F1000280F391F4A1F5B1F20934E0530934F05F2
:105F20004093500550935105213999E8390794E081
:105F3000490790E059070CF03FC02137A6E73A0720
:105F4000ABEF4A07AFEF5A070CF46FC080916005C2
:105F5000909161059C01442737FD4095542F809115
:105F6000520590915305A0915405B0915505280F05
:105F7000391F4A1F5B1F20935205309353054093EE
:105F80005405509355052139B9E83B07B4E04B0758
:105F9000B0E05B078CF120523341494050402093E0
:105FA00052053093530540935405509355051F9166
:105FB0000F91FF90EF900895205233414940504097
:105FC00020934E0530934F05409350055093510553
:105FD000BDCF17FF8CCF80E79CE8A3E0B0E0E80ED0
:105FE000F91E0A1F1B1FE0924A05F0924B05009311
:105FF0004C0510934D057BCF213786E738078BEF93
:1060000048078FEF58079CF6205E3C4E464F5F4F87
:1060100020935205309353054093540550935505F2
:106020001F910F91FF90EF900895205E3C4E464FD8
:106030005F4F20934E0530934F054093500550938A
:10604000510584CF0E94E02D60914805709149056B
:10605000FECE0E94BD290E94032F80915E05909183
:106060005F059093B5038093B40380916005909190
:1060700061059093B7038093B60380914605909194
:1060800047059093B9038093B8038091420590919E
:1060900043059093AF038093AE03809144059091A4
:1060A00045059093B1038093B0038091480590918A
:1060B00049059093B3038093B2030E94482A0E943B
:1060C000B42B08951092CA011092C9011092AD022A
:1060D0001092AC0210924105109240051092AB0252
:1060E0001092AA021092A9021092A8021092A10284
:1060F0001092A00210929F0210929E020E94161906
:1061000060915E0270915F02882777FD8095982FDD
:106110002CEE30E040E050E00E94834060934E055A
:1061200070934F05809350059093510560916002E4
:1061300070916102882777FD8095982F0E94834097
:1061400060935205709353058093540590935505C1
:106150001092620510926305109264051092650515
:10616000609187017091880170938A016093890121
:10617000882777FD8095982F26E832E040E050E0B0
:106180000E94834060934A0570934B0580934C05B1
:1061900090934D0508959C018091C401823031F0A7
:1061A000833081F0813029F0C901089562177307A7
:1061B00064F4620F731F77FD0EC09B013595279520
:1061C000C901089526173707A4F3220F331F261B92
:1061D000370BC90108956F5F7F4FEFCF0F93382FB3
:1061E000E62F8CE398E2632F70E00E94C240709328
:1061F000900160938F01E0936805409367052093B9
:106200006605009369050F9108950F939091BE0163
:106210008091720582FD0EC04091BC012091BB01AE
:10622000265F892F8F5F622F0091C5010E94EE309B
:106230000F91089540E0F2CF0F9381E26AE548E7BD
:106240002AE508E70E94EE300F9108952F923F92C1
:106250004F925F926F927F928F929F92AF92BF9276
:10626000CF92DF92EF92FF920F931F93DF93CF9322
:10627000CDB7DEB7E4970FB6F894DEBF0FBECDBF43
:106280000E94D9200E9429302091830230918402FB
:10629000388F2F8B0E949D20833008F079C4809125
:1062A000DC018A3009F450C3843109F44DC32898C5
:1062B0000E94633E8091C7029091C802009709F442
:1062C0004DC301979093C8028093C70280918802C2
:1062D000909189028150914008F0C7C480918A0250
:1062E0008E7F80938A02E0918502EE2351F08091A7
:1062F000910590E02F89388D8217930714F4988FB9
:106300008F8B2091810230918202A90137FDA0C4B8
:1063100080917B0590E0880F991F880F991F841743
:1063200095070CF422C480917205682F70E0C901B2
:10633000AA2797FDA095BA2F209162053091630599
:106340004091640550916505281B390B4A0B5B0B86
:10635000209362053093630540936405509365056F
:10636000203B8CE338078FEF48078FEF58070CF07E
:10637000E0C380EB9CE3AFEFBFEF809362059093A7
:106380006305A0936405B093650568727070672B10
:1063900009F0E6C38091BA01A82FB0E0BE8BAD8BA7
:1063A0002E2F30E03CA32BA3309167053AA3432F57
:1063B00050E060E070E04E8F5F8F68A379A380911A
:1063C0006805282E332444245524BE016B5F7F4F7B
:1063D0007C8B6B8BCE0109969A8B898B42E4642E61
:1063E00045E0742E36E5832E35E0932E2EE4E22E22
:1063F00025E0F22E5B016C0100E010E080E190E00E
:10640000002E02C0880F991F0A94E2F7ABA1BCA12D
:106410008A239B23892B09F4BEC2F60111821082C4
:10642000D3012D913C91442737FD4095542FC20153
:10643000B1010E94834020E430E040E050E00E943F
:10644000F740F40180819181AD89BE89A89FB00198
:10645000A99F700DB89F700D112477FD96C3759597
:106460006795759567957595679575956795620FAD
:10647000731FF60180819181680F791FD5016D939B
:106480007C93B0EC60307B070CF0B6C220E030ECBF
:10649000F501318320830F5F1F4F22E030E0A20E11
:1064A000B31EC20ED31E620E731E820E931E44E0F4
:1064B00050E0E40EF51E0230110509F09FCFE09187
:1064C0004805F09149052091660590906905A090D6
:1064D0006205B0906305C0906405D0906505809119
:1064E0008F028823C1F080918802909189020297DF
:1064F000C09758F46F89788D1616170634F481E02A
:1065000090E0909389028093880280917C05A82F67
:10651000B0E0B88FAF8B2F88388C220C331C220C44
:10652000331CEE0FFF1FBF01882777FD8095982F42
:1065300030E040E050E00E94834020E430E040E062
:1065400050E00E94F74079018A01692D70E080E0F7
:1065500090E0A60195010E94834020EF35E540E0E0
:1065600050E00E94F740C701820F931FB0E48130D2
:106570009B0714F080E090E49C01E0EC80309E07E3
:1065800014F420E030EC8091810290918202880F17
:10659000991F880F991FA901481B590BF1EA2F1663
:1065A00031040CF4B7C2C10137FC6DC395958795D2
:1065B00022273327281B390B421753073CF0910140
:1065C00035952795421753070CF447C380917D05F5
:1065D000682F70E0788B6F87CB01880F991F880F29
:1065E000991F7101E81AF90A2E153F053CF082192E
:1065F00093097901821793070CF47C019701F7FC4A
:1066000022C335952795220D331DB901882777FDC3
:106610008095982F2091CC0130E040E050E00E941E
:10662000834020E430E040E050E00E94F740390130
:1066300044245524421A530A80918F01909190016D
:106640009C0140E050E02A8F3B8F4C8F5D8F09EC1E
:10665000A02E02E0B02E1DE7812E12E0912E00E068
:1066600010E03AA1332309F4ABC1D4016D917C91C0
:10667000E989FA8920813181261B370B442737FDB0
:106680004095542FF50180819181A281B381820FC1
:10669000931FA41FB51F80839183A283B383AB890B
:1066A000BC89CD90DC90C61AD70AF801EE0FFF1F07
:1066B000EE0FFF1FE753FD4F60817181828193814F
:1066C000603026E072072FEF82072FEF92070CF061
:1066D000A4C140E056E06FEF7FEF408351836283B7
:1066E000738360E076E08FEF9FEF2A8D3B8D4C8DBA
:1066F0005D8D0E94F7402C0D3D1DF801EE0FFF1F30
:1067000081E090E08C0F9D1FE80FF91F31832083FB
:10671000241535050CF07AC1518240820F5F1F4F5E
:10672000A4E0B0E0AA0EBB1EE989FA893296FA8B82
:10673000E98B22E030E0820E931E4B895C894E5F2C
:106740005F4F5C8B4B8B0230110509F08ACF49817A
:106750005A815093C1034093C0032B813C813093F5
:10676000C3032093C203F092C503E092C4033092A6
:10677000C7032092C60380917C05682F70E07E8756
:106780006D8770913902798FF4ED4F2EF4E05F2E12
:10679000E4ED8E2EE3E09E2E74EDA72E75E0B72E6D
:1067A0006FEA662E62E0762ECC24DD24C901AA278A
:1067B00097FDA095BA2F8DA39EA3AFA3B8A7BA014A
:1067C000882777FD8095982F69A77AA78BA79CA724
:1067D000C101AA2797FDA095BA2F8DA79EA7AFA7A5
:1067E000B8AB9701442737FD4095542F29AB3AABFE
:1067F0004BAB5CAB93C0D5013C9013140CF092C032
:1068000012966C91772767FD7095872F972F2DA192
:106810003EA14FA158A50E94834020E430E040E013
:1068200050E00E94F74079018A01F50161817727E4
:1068300067FD7095872F972F29A53AA54BA55CA5D5
:106840000E94834020E430E040E050E00E94F740A6
:10685000E20EF31E232D332727FD3095432F532FB0
:106860006DA57EA58FA598A90E94834020E430E005
:1068700040E050E00E94F740E20EF31ED50113966F
:106880002C91332727FD3095432F532F69A97AA9DF
:106890008BA99CA90E94834020E430E040E050E0B6
:1068A0000E94F740E20EF31EF30160817181C7017F
:1068B0000E94CB30D3018C9311969C9397FD28C1F5
:1068C0009595879595958795ED85FE858E179F07FC
:1068D0000CF055C0CF01009709F45BC0D2018C9336
:1068E000E3E0EC1528F0D2018C91F4018083118251
:1068F0000894C11CD11C25E030E0420E531E42E03A
:1069000050E0840E951E64E070E0A60EB71E640E83
:10691000751E7CE0C716D10409F491C080918A02EB
:1069200080FD69CFB98DBB23F9F0F601EE0FFF1F93
:10693000EE0FFF1FEC0DFD1DEC52FB4FD601A65CC8
:10694000BD4F8C918083CCCF289A0E94633E80916A
:10695000C7029091C802009709F0B3CC80918A02D7
:106960008E7E80938A02BFCCF601EE0FFF1FEE0FE2
:10697000FF1FEC0DFD1DEC52FB4F1082B1CF2F8598
:106980003889281739070CF0A6CFC901009709F0FC
:10699000A5CF81E0A3CFD7012D913D914D915C9181
:1069A0006E8D7F8D88A199A10E94834028EF3AE2E5
:1069B00040E050E00E94F740F6013183208330CD63
:1069C000EB89FC89C080D180D4018D919C91C81A3B
:1069D000D90A9601442737FD4095542FF50180814F
:1069E0009181A281B381820F931FA41FB51F808361
:1069F0009183A283B38359CE615070440CF44BCD84
:106A0000E0E0F0E4D501ED93FC9345CD621673060A
:106A10000CF084CE7182608281CE61305AEF7507AE
:106A200050E0850750E095070CF45FCE60E07AEF08
:106A300080E090E0608371838283938356CE80E010
:106A40000E94552380919101815080939101882368
:106A500009F045C088E18093910160914E057091E5
:106A60004F0580915005909151052AE030E040E0BB
:106A700050E00E94834024E736E040E050E00E946E
:106A8000F7403093A9032093A803609152057091B9
:106A9000530580915405909155052AE030E040E07F
:106AA00050E00E94834024E736E040E050E00E943E
:106AB000F7403093AB032093AA0360914A0570918D
:106AC0004B0580914C0590914D0526E832E040E061
:106AD00050E00E94F7403093AD032093AC03E4965E
:106AE0000FB6F894DEBF0FBECDBFCF91DF911F91DF
:106AF0000F91FF90EF90DF90CF90BF90AF909F905D
:106B00008F907F906F905F904F903F902F9008955F
:106B10000396D6CECA014135510514F080E590E0C8
:106B20009C014FEF803B94070CF050CD20EB3FEFE2
:106B30004DCD2155334C404050400CF426CC80E5DF
:106B400093ECA0E0B0E08093620590936305A0937E
:106B50006405B093650568727070672B09F41ACCF0
:106B60000E94302CE091850215CC88EE93E0909342
:106B70008C0180938B0180917205682F70E084FDF9
:106B8000D6CB81E080939C02D2CB615F7F4F67CCF4
:106B90000E949D208330B0F080918A028F7E809386
:106BA0008A028091850590E028EE31E0BC01629F69
:106BB000C001639F900D729F900D11249093C802A5
:106BC0008093C7028F89988D8997B4F080918A024B
:106BD00080FF12C08091880290918902AFEF8F3FB1
:106BE0009A0729F0019690938902809388020E9467
:106BF0004D3F0E94053177CB8091880290918902A8
:106C00008F3F910509F058F51092CD021092CE02F7
:106C10001092CF021092D0021092C9021092CA02B2
:106C20001092CB021092CC028A3F910501F781E0CD
:106C300080939C0210926205109263051092640585
:106C400010926505D4CF222733272E193F09D9CCBE
:106C500044275527421B530B5BCB9A01B7CC80913D
:106C60008A02826080938A02C2CF80918405482F75
:106C700050E0588F4F8B80918A02806180938A0206
:106C80000E941C3130CB019691CC80918A028460A5
:106C900080938A028FEF8093D9011092DA0180E20B
:106CA0008093DB010E94F0210895109288051092D4
:106CB000890510928A0588E080938B0585ED809385
:106CC0009C0582E080939D0588E780939E058AE07D
:106CD00080939F050895EAE6F5E082E080936A05D7
:106CE00081E080936B0583E080936C0574E0709382
:106CF0006D0525E020936E05A6E0A0936F0587E063
:106D00008093700558E05093710584E48093720578
:106D10004EE1409373058BEF809375058AE0809375
:106D200076054093740540937805709377055093EA
:106D300079058CE080937A0580937B0550937C05E0
:106D400086EE80937D0580E880937F0580E58093C3
:106D5000800534E6309381056FE56093830583E217
:106D600080938405409385051092860580E2809388
:106D7000870530938C0588E280938D051092B605C7
:106D800092E390938E0586E980938F05209390057A
:106D9000909391052AE52093920590939305109284
:106DA000B5052093940583E480939505109296058C
:106DB00090939B056093A00583EF8093A2058FE0DD
:106DC0008093A1058093A3058DEF8093A405309354
:106DD000A5052093A60525AF26AF8BE487AF80934A
:106DE000AA058093AB051092AC05A093AD05509316
:106DF000AE052093AF054093B0053093B1053093B5
:106E0000B2057093B3050895805090400E943841B8
:106E10000895682F863030F065E082E090E00E94AF
:106E2000504108958823C9F761E082E090E00E9414
:106E30005041089582E090E00E943841863008F485
:106E4000089582E090E063E00E94504183E008955D
:106E5000805090400E945041089581E08093C70582
:106E6000E4EDF5E080E009C090E0908311821282A9
:106E700013828F5F3496803159F08430A8F790E404
:106E800090831182128213828F5F34968031A9F72A
:106E900090E49093D5059093D70580EC8093D90525
:106EA0009093DB058093DE058093DF059093E205E8
:106EB0008093E305A8ECB5E0E2E9F1E087E001901A
:106EC0000D928150E1F708958091C705813011F04E
:106ED00080E0089587EC95E068EE73E04DE450E0C3
:106EE0000E94464181E0089588EE93E00E94384177
:106EF000813011F080E0089587EC95E068EE73E052
:106F00004DE450E00E94284181E008958050904077
:106F10000E945E4108951F93182F863000F115E0FE
:106F200068ED71E0605070408AE695E04DE550E014
:106F30000E94464182E690E06DE570E00E945E416D
:106F40008AE695E060E570E048E050E00E94464146
:106F5000812F0E9409370E94FF1F1F9108958823E7
:106F6000E1F390E001972DE530E0829FB001839F2F
:106F7000700D929F700D11246C597F4FD3CF982FB5
:106F80008150853068F06EE171E0605070408AE6B3
:106F900095E04DE550E00E9428410E94FF1F0895B2
:106FA000892F90E001972DE530E0829FB001839F0B
:106FB000700D929F700D11246C597F4FE6CF805059
:106FC00090400E94404108950E946B360E94C23F4B
:106FD0000E94553680EC8093720583E0809377059C
:106FE00084E18093850586E4809396058EE1809305
:106FF000A1058093A305ABEBB5E0EAE9F1E089E0F8
:1070000001900D928150E1F708950E946B360E9425
:10701000C23F0E94553680EC8093720583E08093D6
:10702000770584E18093A1058093A305ABEBB5E0E0
:10703000E4EAF1E087E001900D928150E1F70895D4
:107040000E946B360E94C23F0E94553680EC8093AE
:107050007205ABEBB5E0ECEAF1E086E001900D9251
:107060008150E1F708950F931F93CF93DF9381E051
:1070700090E00E9438418B3409F44FC000D00F9249
:10708000ADB7BEB711961C9211978DE998E0139693
:107090009C938E9312970E94890F0F900F900F90E0
:1070A00088EE93E06FEF0E94504180E590E00E94EF
:1070B000384100E08C3008F494C080E08F5F843069
:1070C00011F00023D9F711E0123031F0133009F438
:1070D00085C0113009F47FC00E940538002379F083
:1070E000C0E0D0E0CE01805B9F4F0E943841FE019E
:1070F000E659FA4F80832196C830D10599F7812F40
:107100000E948B371F5F1630F9F681E00E94093725
:1071100081E090E06BE40E9450410E941A370E9487
:10712000BF370E941A3700D000D00F92EDB7FEB7DC
:107130003196ADB7BEB711961C9224E838E0328381
:107140002183838314820E94890F0F900F900F90E8
:107150000F900F900E947437882309F444C0E4ED27
:10716000F5E020E0808118160CF42F5F349686E05D
:10717000E431F807B9F72093AE02ADB7BEB7179761
:107180000FB6F894BEBF0FBEADBFEDB7FEB73196D8
:1071900011961C9282E498E09283818388EC95E0BA
:1071A00094838383258316820E94890F0F900F900A
:1071B0000F900F90EDB7FEB7118281E298E09383B4
:1071C00082830E94890F0F900F900F90DF91CF91D3
:1071D0001F910F9108950E94203880CF0E94E437BC
:1071E0007DCF01E06ACF00D00F92EDB7FEB71182DC
:1071F00083E698E0938382830E94890F0F900F901B
:107200000F900E942D370E946437A9CF9FB7F89442
:107210008091C9008F778093C9008091C9008F7BCE
:107220008093C9008091C9008F7D8093C9005A9ACC
:1072300052985B9A539A1092CD008AE28093CC00C8
:107240008091C80082608093C80088E18093C90063
:107250008091CA008F778093CA008091CA008F7B8B
:107260008093CA008091CA008F7D8093CA0080916C
:10727000CA008F7E8093CA008091CA00877F809366
:10728000CA008091C9008B7F8093C9008091CA0099
:1072900084608093CA008091CA0082608093CA0093
:1072A0008091C80087FF06C08091CE008091C80001
:1072B00087FDFACF8091C90080688093C9009FBF85
:1072C00008951F920F920FB60F9211248F93809101
:1072D000CE008F910F900FBE0F901F901895809148
:1072E000AA049091AB04A091AC04B091AD0420919C
:1072F0002406309125064091260650912706281B2A
:10730000390B4A0B5B0BB901CA0108958091AA049D
:107310009091AB04A091AC04B091AD04809324068D
:1073200090932506A0932606B09327062091AA04E1
:107330003091AB044091AC045091AD04821B930B8F
:10734000A40BB50B8093180690931906A0931A0608
:10735000B0931B0610921406109215061092160692
:107360001092170610921C0610921D0610921E060F
:1073700010921F0608958F929F92AF92BF92CF9264
:10738000DF92EF92FF920F931F938091AA04909146
:10739000AB04A091AC04B091AD044091240650918F
:1073A00025066091260670912706481B590B6A0B2B
:1073B0007B0B8091140690911506A0911606B09152
:1073C000170684179507A607B70744F440931406D9
:1073D00050931506609316067093170680917205F8
:1073E00081FF55C08091A60381608093A6038091A0
:1073F000B6018852803B08F47EC09091DC0299323D
:1074000008F05AC0983209F47EC09F5F9093DC0266
:107410008091D7028F5F8093D702803309F054C0E8
:107420001092D70280917705882E9924AA24BB2434
:10743000C0901806D0901906E0901A06F0901B062E
:10744000950184010C0D1D1D2E1D3F1D80912006F0
:1074500090912106A0912206B091230680179107F2
:10746000A207B3075CF497018601081919092A09D4
:107470003B09081719072A073B0734F10093180640
:107480001093190620931A0630931B061DC0809195
:10749000A6038E7F8093A6038091B60124E6829F87
:1074A000C0011124A0E0B0E0809320069093210653
:1074B000A0932206B09323068091D7028F5F80931A
:1074C000D702803309F4ACCFCB01BA0124E630E017
:1074D00040E050E00E94F7403093E5032093E4033E
:1074E0001F910F91FF90EF90DF90CF90BF90AF90E2
:1074F0009F908F9008951092DC028091A7038E7F59
:107500008093A703D9CF4093200650932106609320
:107510002206709323068091A70381608093A703BE
:1075200074CFCF92DF92EF92FF920F931F93CF937E
:10753000DF936C018091AA049091AB04A091AC04FC
:10754000B091AD0420912406309125064091260685
:1075500050912706281B390B4A0B5B0BE09018064D
:10756000F090190600911A0610911B068091D8021E
:107570009091D902E901C81BD90B2093D80230930E
:10758000D9024093DA025093DB021C161D060CF060
:10759000BEC08091A60382608093A6038091A7035A
:1075A0008D7F8093A703E21AF30A040B150B209139
:1075B000760530E040E050E0C801B7010E9483400A
:1075C00028EE33E040E050E00E94F74080917405DF
:1075D00090E0BC01C69FC001C79F900DD69F900D43
:1075E0001124281B390B80917305482F50E0421756
:1075F00053074CF088279927841B950BA90128175E
:1076000039070CF466C08091720580FF04C081FDCB
:1076100075C0C40ED51E7E010027F7FC0095102F03
:107620006091D1027091D2028091D3029091D402E4
:1076300028E130E040E050E00E948340E60EF71E73
:10764000081F191FC801B70129E130E040E050E0F0
:107650000E94F74079018A01E092D102F092D202B1
:107660000093D3021093D4022091B3013091B4015E
:10767000C901880F991F820F931F880F991F880FC8
:10768000991F880F991F8C0D9D1D69E170E00E9464
:10769000AE406093B3017093B401809188029091E1
:1076A0008902885E934030F083E0E816F10401051A
:1076B00011058CF08091A6038B7F8093A603C601F1
:1076C000DF91CF911F910F91FF90EF90DF90CF90BE
:1076D0000895AC0198CF2EEFE2162FEFF2062FEFB0
:1076E00002072FEF120734F36093D5027093D6028E
:1076F0008091A60384608093A603E1CF8091B601B8
:107700008852803B08F487CFC40ED51E84CF2097C3
:1077100009F449CF8091A70382608093A7038091E9
:10772000A6038D7F8093A6033ECFCF93DF93E09196
:107730007505EF3F59F0EB3F08F4ACC1F0E0EE0FF8
:10774000FF1FE951FF4F80818093B601E0917405DE
:10775000EF3F59F0EB3F08F49AC1F0E0EE0FFF1F46
:10776000E951FF4F80818093B5018091B501882355
:1077700009F04AC11092B501E0917605EF3F59F04A
:10778000EB3F08F481C1F0E0EE0FFF1FE951FF4F1E
:1077900080818093B7018091B701882309F02DC1C2
:1077A0001092B701E0917805EF3F59F0EB3F08F4F4
:1077B00068C1F0E0EE0FFF1FE951FF4F8081809319
:1077C000B801E0917F05EF3F59F0EB3F08F456C157
:1077D000F0E0EE0FFF1FE951FF4F80818093B90168
:1077E000E0918005EF3F59F0EB3F08F444C1F0E031
:1077F000EE0FFF1FE951FF4F80818093BB01809105
:10780000BB018B3008F0F3C08AE08093BB01E091AC
:107810008105EF3F59F0EB3F08F42AC1F0E0EE0F8D
:10782000FF1FE951FF4F80818093BC01E0918205E9
:10783000EF3F59F0EB3F08F418C1F0E0EE0FFF1FE7
:10784000E951FF4F80818093BA01E0918705EF3FB6
:1078500059F0EB3F08F406C1F0E0EE0FFF1FE951CD
:10786000FF4F80818093BE01A8E8B5E0CFEBD1E067
:10787000EC91EF3F51F0EB3F08F4B7C0F0E0EE0FB2
:10788000FF1FE951FF4F808188831196219685E083
:10789000AC38B80769F75096C3ECD1E0EC91EF3FF4
:1078A00051F0EB3F08F49FC0F0E0EE0FFF1FE951ED
:1078B000FF4F808188831196219685E0A03AB80712
:1078C00069F7E0918C05EF3F59F0EB3F08F4C7C032
:1078D000F0E0EE0FFF1FE951FF4F80818093C70159
:1078E000E0919105EF3F59F0EB3F08F4B5C0F0E0AF
:1078F000EE0FFF1FE951FF4F80818093C801E09197
:107900009405EF3F59F0EB3F08F4A3C0F0E0EE0F11
:10791000FF1FE951FF4F80818093C901E0919505D8
:10792000EF3F59F0EB3F08F491C0F0E0EE0FFF1F7E
:10793000E951FF4F80818093CA01E0919605EF3FA6
:1079400059F0EB3F08F47FC0F0E0EE0FFF1FE95164
:10795000FF4F80818093CB01E0919B05EF3F59F071
:10796000EB3F08F46DC0F0E0EE0FFF1FE951FF4F51
:1079700080818093CC01E091A105EF3F59F0EB3F6E
:1079800008F453C0F0E0EE0FFF1FE951FF4F808174
:107990008093CE018091CE01823008F44DC08F3F9C
:1079A00009F486C0E091A305EF3F51F0EB3F98F159
:1079B000F0E0EE0FFF1FE951FF4F80818093CF0170
:1079C0008091CF01823068F18F3F09F474C0E0915B
:1079D000B405EF3F29F0EB3F08F05FC0E093CD0125
:1079E000DF91CF910895E88366CFE8834ECF8F3F34
:1079F00009F00DCF8093BB010ACF843608F4D2CEB4
:107A000084E68093B701CECE843608F4B5CE84E602
:107A10008093B501B1CEE093CF018091CF01823048
:107A200098F681E08093CF01D2CFE093CE01809190
:107A3000CE01823008F0B3CF81E08093CE01B2CF87
:107A4000E093CC0198CFE093CB0186CFE093CA01BD
:107A500074CFE093C90162CFE093C80150CFE093A7
:107A6000C7013ECFE093BE01FFCEE093BA01EDCE59
:107A7000E093BC01DBCEE093BB01C1CEE093B90142
:107A8000AFCEE093B8019DCEE093B70184CEE093F2
:107A9000B5016BCEE093B60159CEF0E0EE0FFF1FBB
:107AA000E951FF4F80818093CD01DF91CF910895FF
:107AB0008093CE0177CF8093CF0189CF962F8B3FD4
:107AC00038F4682F691768F0461770F0862F08950C
:107AD000E82FF0E0EE0FFF1FE951FF4F60816917BB
:107AE00098F7692F862F0895642F862F0895CF93D6
:107AF000DF93ADEDB1E06DE570E08C9190E0869F95
:107B0000F001879FF00D969FF00D1124E659FA4F72
:107B1000408111968C9111974F3FE9F04B3F38F01F
:107B2000E42FF0E0EE0FFF1FE951FF4F408190E09E
:107B3000FC01EE0FFF1FEE0FFF1FEE0FFF1F9F0157
:107B4000220F331F220F331FE20FF31FE81BF90B25
:107B5000EB54FE4F4083129682E0A730B80769F6D7
:107B6000C7E0D2E099976DE570E0888190E0869F4C
:107B7000F001879FF00D969FF00D1124E659FA4F02
:107B8000E0818C91EF3F21F14A819B81EB3F30F006
:107B9000F0E0EE0FFF1FE951FF4FE081E41720F006
:107BA0004E2F9E1708F4492F90E0FC01EE0FFF1FA7
:107BB000EE0FFF1FEE0FFF1F9F01220F331F220F3B
:107BC000331FE20FF31FE81BF90BEB54FE4F40830A
:107BD0002496129682E0CF31D80739F6A0E5B0E1BD
:107BE000CBE3D3E0EC91EF3F49F0EB3F30F0F0E036
:107BF000EE0FFF1FE951FF4FE081E883A35ABF4F0B
:107C0000A79681E1A43CB80769F7A4E9B7E1C7EDFD
:107C1000D3E0EC91EF3F49F0EB3F30F0F0E0EE0FB6
:107C2000FF1FE951FF4FE081E883A35ABF4FA7969A
:107C300089E1A830B80769F7DF91CF910895809165
:107C4000C800803219F090E0892F08958091CA0011
:107C500090E08630C9F791E0892F089585B18C7F37
:107C600085B9209888EE93E00197F1F783B190E011
:107C70008370907081309105A9F08230910569F090
:107C8000892BB1F484B1836084B98AE0289A8C305E
:107C900010F0299A08952998089584B1836084B9D1
:107CA00084E1F4CF84B1836084B98BE02898EFCF6E
:107CB00084B1836084B98DE02898E9CF909357020E
:107CC00080935602089580910401909105018F5F81
:107CD0009F4F09F0089588E99AE3909357028093A3
:107CE000560280E09CE09093050180930401089582
:107CF00080910401909105018F5F9F4F09F00895D5
:107D000080918A0280FFFBCF80E197E29093570237
:107D10008093560280E890E09093050180930401DF
:107D2000089580E093E09093050180930401809191
:107D3000560290915702892B31F480E797E1909396
:107D4000570280935602089587E090E090930501D2
:107D5000809304018091560290915702892B31F44F
:107D600080E797E1909357028093560208951F93FE
:107D7000CF93DF93982F8823C1F080918A0280FDF2
:107D800014C0192F1150C4E6D0E005C080918A02BA
:107D9000115080FD0AC0D0935702C09356028AEF5B
:107DA00090E00E940313112389F7DF91CF911F9177
:107DB0000895DF92EF92FF920F931F93CF93DF937B
:107DC000EC0160914E0570914F05809150059091A6
:107DD00051050E94D8227C01609152057091530593
:107DE00080915405909155050E94D822AA2797FDAD
:107DF000A095BA2F0027F7FC0095102FBC01CD01EC
:107E0000A80197010E948340D090C1019B01AC0161
:107E10002030E0E03E07E0E84E07E0E05E0778F162
:107E20002150304040485F4F2F5F3F4F4F475040F9
:107E300030F1ED2CFF2400E010E01E2D0027FF2480
:107E4000EE242AE030E040E050E00E94F740C80114
:107E5000B7010E94F7408D2D90E0BC01660F771F9F
:107E6000660F771F660F771F880F991F680F791F9E
:107E700088279927861B970B820F931F02C080E0EB
:107E800090E09C012C0F3D1FC901DF91CF911F9104
:107E90000F91FF90EF90DF9008950F931F930E9432
:107EA0009420182F0E949720082F0E949120982F2D
:107EB00080918A0280FD05C0123021F1143009F44E
:107EC0003FC0163089F0183019F01F910F910895B6
:107ED000109289021092880280918A028E7F80938C
:107EE0008A021F910F91089581E090E0909389029A
:107EF0008093880280918A02896080938A021F9110
:107F00000F910895002309F78091DC018C3010F166
:107F1000299A963018F5892F8150853078F10E9482
:107F20001A370E94BF370E9462300E9445360E9475
:107F300002220E941A370E94B73E1F910F910895A6
:107F4000002319F68091DC018C3030F0299A0E94D0
:107F50005218E9CF2998DDCF2998F9CF8091720581
:107F6000887209F4B2CF973009F0AFCF81E08093E7
:107F70009D0288EE93E00E945E3EA7CF892F0E946B
:107F80000937CDCF83E08093820581E080937E0521
:107F90008AE080939A0585E58093970580939805FC
:107FA0000895559B02C05D9906C05D9A559A84E676
:107FB00090E00E9403135D9881E090E00E9403131B
:107FC0005D9A84E690E00E94181308953C98449AC4
:107FD0001092290210922E0681E080932F060895B8
:107FE0008091EE029091EF0201969093EF028093C0
:107FF000EE0201978858934109F475C0349B12C072
:108000008091F2029091F30201969093F302809393
:10801000F2028159914008F052C020912902222396
:1080200089F108956091F2027091F302CB010197FA
:108030008956914010F56A30710508F45FC06A50A6
:10804000704080E090E029E134E040E050E00E94A0
:1080500083402AE096958795779567952A95D1F77D
:1080600070938801609387018091A70390E489272A
:108070008093A7038CE0809329021092F302109260
:10808000F202CBCF8091F0029091F1020E94F9129E
:10809000882339F28091560290915702892B31F44E
:1080A00084E690E0909357028093560284E690E035
:1080B0000E94EF129093F1028093F00208952091B4
:1080C0002902222329F0822F815080932902282F10
:1080D0008FEF9FEF90938801809387011092F302B6
:1080E0001092F2029CCF8091A60390E4892780939E
:1080F000A6031092EF021092EE0280CF1092880138
:1081000010928701B7CF629FD001739FF001829FC9
:10811000E00DF11D649FE00DF11D929FF00D839F16
:10812000F00D749FF00D659FF00D9927729FB00DB3
:10813000E11DF91F639FB00DE11DF91FBD01CF01C6
:1081400011240895991B79E004C0991F961708F02F
:10815000961B881F7A95C9F780950895AA1BBB1BAB
:1081600051E107C0AA1FBB1FA617B70710F0A61B37
:10817000B70B881F991F5A95A9F780959095BC0158
:10818000CD01089597FB092E07260AD077FD04D06C
:10819000E5DF06D000201AF4709561957F4F0895B1
:1081A000F6F7909581959F4F0895A1E21A2EAA1B8C
:1081B000BB1BFD010DC0AA1FBB1FEE1FFF1FA21797
:1081C000B307E407F50720F0A21BB30BE40BF50B94
:1081D000661F771F881F991F1A9469F7609570951D
:1081E000809590959B01AC01BD01CF01089597FB4F
:1081F000092E05260ED057FD04D0D7DF0AD0001C6B
:1082000038F450954095309521953F4F4F4F5F4F33
:108210000895F6F790958095709561957F4F8F4FF3
:108220009F4F0895FB01DC0102C005900D92415063
:108230005040D8F70895FC014150504030F0019073
:108240000616D1F73197CF01089588279927089509
:10825000DC01CB01FC01F999FECF06C0F2BDE1BD06
:10826000F89A319600B40D9241505040B8F70895F5
:10827000F999FECF92BD81BDF89A992780B50895EE
:10828000A8E1B0E042E050E00C942A41DC01CB01CF
:1082900003C02D910E94514141505040D0F70895A4
:1082A000262FF999FECF1FBA92BD81BD20BD0FB612
:1082B000F894FA9AF99A0FBE019608950E945041D7
:0A82C000272F0C945141F894FFCFD2
:1082CA00FF01F401FFFF0100080008000400040098
:1082DA000400026A640001000000000000000000BF
:1082EA00000000000000000000000000000000196B
:1082FA0000020D48656C6C6F20576F726C64000049
:10830A000000000000000000000000000000000063
:10831A000000000000000000000000000000000053
:10832A000000000000000000000000000000000043
:10833A000000000000000000000000000000000033
:10834A0000000064000101FFFFFFFFF40100013893
:10835A00010151756164726F0000426567696E6E52
:10836A00657200004E6F726D616C000053706F721F
:10837A00740000320030FB103A40089696020A0058
:10838A000000000000000064465A414064000000FA
:10839A000000000000000000000000000D0B010EAC
:1083AA00031504170718051D09221227132A142B6F
:1083BA00152C1631173A1B3B1C3C1D3D1E3E1F4215
:1083CA0020452246234A180A0000640C000096162B
:1083DA000600FF371901FF391A01FF47210AFF007A
:0A83EA000080000000000000010CFC
:00000001FF
/branches/dongfang_FC_rewrite/Flight-Ctrl_MEGA644p_NAVICTRL__ADXRS610_FC2.0_V0_74df_SVN0001.hex
0,0 → 1,2150
:100000000C943B040C9458040C9458040C9458041D
:100010000C9458040C9458040C9458040C945804F0
:100020000C9458040C9400130C9458040C94580429
:100030000C9409250C9458040C9458040C945804FE
:100040000C9458040C9458040C941D120C945804ED
:100050000C948C060C9458040C9455060C9458047B
:100060000C9458130C9458040C949B220C94580430
:100070000C942C380C9458040C9458040A0A0D0063
:100080004E65757472616C20284143432D4D6F6439
:1000900065290048656164696E67486F6C64000A91
:1000A0000D436F6E74726F6C3A20000A0D537570B9
:1000B000706F727420666F72204E6176694374723D
:1000C0006C000A0D3D3D3D3D3D3D3D3D3D3D3D3DD1
:1000D0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D50
:1000E0003D3D3D3D3D3D3D000A0D3D3D3D3D3D3DE0
:1000F0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D30
:100100003D3D3D3D3D3D3D3D3D3D3D3D3D000A0DBF
:10011000536F6674776172653A205625642E2564A4
:1001200025630070000D0A20202020204350553AFE
:100130002041746D656761363434000A0D48617280
:1001400064776172653A20437573746F6D000A0DB0
:10015000466C69676874436F6E74726F6C000A0D49
:100160003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3DBF
:100170003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3DAF
:100180003D3D3D00416E676C655069746368202099
:1001900020202020416E676C65526F6C6C202020FF
:1001A00020202020416E676C655961772020202037
:1001B000202020204779726F506974636828504965
:1001C000442920204779726F526F6C6C2850494443
:1001D000292020204779726F596177202020202024
:1001E000202020204779726F50697463682841434A
:1001F000292020204779726F526F6C6C2841432967
:10020000202020204779726F5961772841432920A7
:100210002020202041636350697463682028616E48
:10022000676C6529416363526F6C6C2028616E674F
:100230006C65292055426174202020202020202038
:10024000202020205069746368205465726D20203E
:1002500020202020526F6C6C205465726D2020206D
:1002600020202020596177205465726D20202020A5
:10027000202020205468726F74746C65205465725D
:100280006D202020307468204F20436F72722070E0
:1002900069746368307468204F20436F72722072F3
:1002A0006F6C6C204472696674436F6D7044656C4A
:1002B000746120504472696674436F6D7044656C5C
:1002C00074612052414450697463684779726F4F7A
:1002D000666673204144526F6C6C4779726F4F664B
:1002E000667320204D312020202020202020202037
:1002F000202020204D3220202020202020202020BF
:10030000202020204D3320202020202020202020AD
:10031000202020204D34202020202020202020209C
:1003200020202020436F6E74726F6C5961772020FB
:100330002020202041697270726573732E205261F3
:100340006E6765204472696674436F6D705069749E
:10035000636820204472696674436F6D70526F6CDD
:100360006C202020416972707265737346696C74E9
:1003700065726564416972707265737341444320AC
:1003800020202020020100070603020105020100CF
:100390000706030201043132003131003130002000
:1003A00025632020202D2020202D2020202D2000FE
:1003B0002025632020202563202020256320202065
:1003C0002563200020256320202025632020202570
:1003D0006320202025632000424C2D4374726C2042
:1003E000666F756E642000202533642020253364F9
:1003F0002020253364202025336420002025336409
:1004000020202533642020253364202025336420D8
:1004100000202533642020253364202025336420E8
:10042000202533642000424C2D4374726C204572A9
:10043000726F7273200048693A2534692020436640
:100440003A253469200047733A25346920205961E0
:100450003A25346920004E693A2534692020526FCC
:100460003A253469200045787465726E436F6E7466
:10047000726F6C202000506F343A20253369205071
:100480006F383A2025336900506F333A202533699D
:1004900020506F373A2025336900506F323A2025BB
:1004A000336920506F363A2025336900506F313A56
:1004B0002025336920506F353A20253369004F6677
:1004C00066436F757273653A20253569004865612A
:1004D00064696E673A20202025356900436F757284
:1004E00073653A2020202025356900436F6D7061C7
:1004F0007373202020202020200052432D4C65764D
:10050000656C3A2025356900566F6C746167653AF1
:1005100020202533692E253169560050333A253481
:1005200069202050343A253469200050313A25346E
:1005300069202050323A253469200047733A253427
:1005400069202059613A25346920004E693A2534E2
:10055000692020526F3A253469200043373A253408
:1005600069202043383A253469200043353A253440
:1005700069202043363A253469200043333A253434
:1005800069202043343A253469200043313A253428
:1005900069202043323A2534692000486561646946
:1005A0006E673A20202025356900526F6C6C3A2026
:1005B0002020202020253569004E69636B3A2020D9
:1005C00020202020253569004174746974756465A4
:1005D0000028632920486F6C676572204275737329
:1005E000004D697373696E6720424C2D4374726CC1
:1005F0003A256400493243204572726F72212121ED
:100600000053657474696E673A2025642025730071
:1006100048573A5625642E25642053573A25642EB0
:1006200025642563002B204D696B726F4B6F7074CE
:100630006572202B005B25695D005B25695D00000C
:100640000047008F00D6001E016501AC01F3013A9E
:10065000028102C7020E0354039903DF03240469D5
:1006600004AE04F20436057905BC05FE0540068299
:1006700006C306040744078307C20700083E087B39
:1006800008B708F2082D096809A109DA09120A4910
:100690000A7F0AB50AE90A1D0B500B820BB40BE462
:1006A0000B130C420C6F0C9C0CC70CF20C1B0D4472
:1006B0000D6B0D920DB70DDB0DFE0D210E420E617F
:1006C0000E800E9E0EBA0ED60EF00E090F210F38B8
:1006D0000F4D0F610F740F860F970FA60FB50FC246
:1006E0000FCE0FD80FE10FEA0FF00FF60FFA0FFE43
:1006F0000FFF0F0010000047008F00D7001E01669B
:1007000001AF01F70140028902D2021C036703B264
:1007100003FD034A049704E40433058205D305244A
:10072000067706CB0620077607CE0727088208DE65
:10073000083D099D09FF09640ACB0A340BA00B0F81
:100740000C800CF50C6D0DE90D680EEC0E730F00AE
:100750001092102811C51168121113C2137B143C9A
:10076000150616DA16B917A3189B19A11AB61BDDC0
:100770001C171E671FCE205022F023B2259A27AEE9
:1007800029F62B782E3E315534CC37B63B2C404ED3
:1007900045464B5052BE5A0565D971FF7FFF7FFF1A
:1007A0007FFF7FFF7FFF7FFF7FFF7F0A0D0A0D2105
:1007B00021204D495353494E4720424C2D4354521A
:1007C0004C3A20256420212100256420000A0D4692
:1007D0006F756E6420424C2D4374726C3A20000A8F
:1007E0000D3D3D3D3D3D3D3D3D3D3D3D3D3D3D3D69
:1007F0003D3D3D3D3D3D3D3D3D3D3D3D3D3D3D0066
:100800000A0D4D697865722D436F6E6669673A20EF
:100810002725732720282575204D6F746F72732943
:10082000000A0D47656E65726174696E67206465C4
:100830006661756C74204D69786572205461626CD4
:1008400065000A0D5573696E6720506172616D65B0
:1008500074657220536574202564000A0D496E6921
:100860007420506172616D6574657220696E2045F7
:100870004550524F4D0011241FBECFEFD0E1DEBFD7
:10088000CDBF12E0A0E0B1E0ECE1F5E802C00590D8
:100890000D92A033B107D9F716E0A0E3B2E001C092
:1008A0001D92AF38B107E1F70E945A040C948C42B4
:1008B0000C940000EF92FF921F93CF93DF93F89474
:1008C0000E94EA3C8093F7020E94F93C982F8093A3
:1008D000DC0184B7877F84BF80916000886180934A
:1008E0006000109260009A3009F4B0C1943109F4AC
:1008F000ADC1289A0E94111F0E94EF110E94D012D0
:100900000E94E0078091F702813009F4A1C10E94A2
:10091000D5240E940A130E9436220E949F3E78949A
:1009200000D00F92ADB7BEB711961C9211978EE50D
:1009300091E013969C938E9312970E94B70EEDB799
:10094000FEB711828EE491E0938382830E94B70EFA
:10095000ADB7BEB711961C9211978BE391E0139639
:100960009C938E9312970E94B70EEDB7FEB711823B
:1009700085E291E0938382830E94B70E0F900F90DF
:100980000F908091F702813009F47CC1EDB7FEB77A
:1009900039970FB6F894FEBF0FBEEDBF3196ADB7D5
:1009A000BEB711961C928EE091E0928381831482EF
:1009B00013828AE490E09683858385EC90E09087AB
:1009C00087830E94B70EEDB7FEB736960FB6F89440
:1009D000FEBF0FBEEDBF118288EE90E0938382834D
:1009E0000E94B70E0F900F900F900E94FE3688EC79
:1009F00090E00E948612EC01429A8091DC018C30DA
:100A000008F03EC129988A3009F41EC1843109F4E6
:100A10001BC12898CE010E9490128823D9F388EC3C
:100A200090E00E948612EC014298439A8091DC018A
:100A30008A3009F407C1843109F404C1289A8C3042
:100A400008F01CC1299ACE010E9490128823D9F384
:100A500088EC90E00E948612EC01CE010E94901278
:100A60008823D9F343980E94272400D00F92ADB772
:100A7000BEB711961C92119782EC90E013969C934E
:100A80008E9312970E94B70EEDB7FEB711828BEAD4
:100A900090E0938382830E94B70E0F900F900F9087
:100AA0000E9405210E94342F0E94F8120E941035E6
:100AB00080ED97E00E94293D00D00F92ADB7BEB700
:100AC00011961C9211978FE990E013969C938E9348
:100AD00012970E94B70E80917D050F900F900F9096
:100AE00082FFB9C000D00F92EDB7FEB7118283E943
:100AF00090E0938382830E94B70E0F900F900F9027
:100B000000D00F92EDB7FEB711828CE790E093838F
:100B100082830E94B70E0F900F900F900E942019B1
:100B200088E893E1909384018093830114E085E049
:100B3000E82EF12C80915902882321F08091160132
:100B4000882371F480915E028823A1F70E94D33E2E
:100B5000809159028823B1F380911601882391F383
:100B6000109259025C9A0E94F82F5C982091DC0147
:100B70002A3009F45EC0243109F45BC0289A8091C0
:100B80008301909184010197909384018093830164
:100B90008091830190918401892BC9F18091960203
:100BA0008823A9F52A3009F448C0243109F445C046
:100BB000289A80915902882321F08091910280FD2A
:100BC00002C00E9466090E94460CCE010E9490124B
:100BD0008823D1F0809114019091150118161906FF
:100BE00054F4209114013091150180918E0590E00C
:100BF0002817390724F10E94714110935E0284E1A5
:100C000090E00E948612EC010E94911F9BCF2A3037
:100C100091F0243181F02898809183019091840192
:100C2000892B39F60E947222F0928401E0928301AE
:100C3000C0CF2898A4CF289AEFCF2898BACF0E9487
:100C40005C3DD9CF2898FBCE289AE4CE289852CE86
:100C50000E94D1375CCE00D00F92ADB7BEB71196CF
:100C60001C92119780E890E013969C938E931297B4
:100C70000E94B70E0F900F900F9042CF2998E3CEAD
:100C8000299AC1CE00D00F92ADB7BEB711961C9273
:100C9000119783E291E013969C938E9312970E9492
:100CA000B70E0F900F900F9071CE1F920F920FB64C
:100CB0000F9211248F939F93EF93FF9380910101E3
:100CC0008823A9F480915502909156020196909341
:100CD000560280935502FC01ED50FC4FE081ED304F
:100CE00099F08639910581F0E093C60004C0109216
:100CF000560210925502FF91EF919F918F910F90A4
:100D00000FBE0F901F901895109256021092550228
:100D100081E080930101E8CF1F920F920FB60F92EE
:100D200011242F933F934F935F936F938F939F93D0
:100D3000AF93BF93CF93DF93EF93FF936091C60080
:100D400080913A02882351F4309152023323C1F04A
:100D50003639C8F01092520210923A02FF91EF9188
:100D6000DF91CF91BF91AF919F918F916F915F91E3
:100D70004F913F912F910F900FBE0F901F9018959C
:100D8000633209F43FC06D3099F0E32FF0E0EF5F7C
:100D9000FC4F60833F5F30935202809153029091E9
:100DA0005402860F911D9093540280935302D6CF24
:100DB000A32FB0E0FD01E150FD4F9081ED01C05047
:100DC000DD4F88814091530250915402491B5109D3
:100DD000481B51095F705093540240935302208185
:100DE000CA010024880F991F001C880F991F001C3E
:100DF000892F902D835C281789F010923A02109267
:100E00005202ACCF6093010381E08093520283E2EF
:100E100090E09093540280935302A0CF9881842F46
:100E20008F73835C981749F7AF5FBC4F6C933F5F3C
:100E300030933B0281E080933A0280910303823534
:100E4000F1F62CE088E190E00FB6F894A895809335
:100E500060000FBE20936000D2CFCF93DF93BC0120
:100E60000097A9F140E050E020E030E0FA01ED50B9
:100E7000FC4F8081280F311D4F5F5F4F461757078A
:100E8000A8F33F70C9010024880F991F001C880F28
:100E9000991F001C892F902D835CDB0111962F7305
:100EA000235CED012196FB01ED50FC4F8083AD509A
:100EB000BC4F2C93CD50DC4F8DE088831092010104
:100EC0008091F3038093C600DF91CF910895E0E015
:100ED000F0E08DE3A1E0B0E02DE3C2E0D0E0E4CFAC
:100EE00050913B02565009F457C033E043E01EC016
:100EF000972F9D53F0E02295207F892F8695869528
:100F0000282BEF5FFC4F2083E42FEE5F5230C1F1BE
:100F10005350F0E09295990F990F907C6D53962B5A
:100F2000EF5FFC4F90834D5F5523A1F1E32FF0E07D
:100F3000EF5FFC4F80813F5FE32FF0E0EF5FFC4FFE
:100F400020812D533F5FE32FF0E0EF5FFC4F708176
:100F50003F5FE32FF0E0EF5FFC4F60813F5F922F38
:100F600092959F708D53880F880F892BE42FF0E0A6
:100F7000EF5FFC4F8083E42FEF5F513009F0B8CF73
:100F8000E35084E093E090933D0280933C02E09331
:100F90003E020895E42FF4CFE0E0F3CF1F93182F23
:100FA0008A3051F08091C00085FFFCCF1093C600BD
:100FB00080E090E01F9108958DE00E94CE07F2CF6F
:100FC0001F931FB7F8948091C1008F778093C10061
:100FD0008091C1008F7B8093C100589A5098599A94
:100FE000519A1092C5008AE28093C4008091C0009B
:100FF00082608093C00088E18093C1008091C2002C
:101000008F778093C2008091C2008F7B8093C20053
:101010008091C2008F7D8093C2008091C2008F7E3C
:101020008093C2008091C200877F8093C20080912C
:10103000C1008B7F8093C1008091C2008460809347
:10104000C2008091C20082608093C2008091C00083
:1010500087FF06C08091C6008091C00087FDFACF4F
:101060008091C10080688093C1008091C10080643C
:101070008093C10080910201909103010E94861229
:1010800090938A048093890410923A0210923D0250
:1010900010923C0210923E0291E090930101109256
:1010A000A7038AE48093A80384E68093AB038AE0D5
:1010B0008093A9039093AA031FBF1F910895BF9225
:1010C000CF92DF92EF92FF920F931F93DF93CF9314
:1010D000CDB7DEB78D852E8593E29093F3038F59BC
:1010E0008093F4038C858093F503222379F463E0E5
:1010F00070E0CB010E942D07CF91DF911F910F91DE
:10110000FF90EF90DF90CF90BF900895EF84F88824
:1011100003E1C02ED12CCC0EDD1E49895A89411520
:10112000510529F3022F015063E070E010E062C026
:10113000A12FB0E01F5FFA01AE0DBF1D8C91AF0172
:101140004150504009F48BC0E12FF0E01F5FEE0DDD
:10115000FF1DA0814150504009F06DC0002309F4EB
:101160006AC096012E5F3F4FF601E080F18012E0E9
:10117000C12ED12CC20ED31EF901408151810150E4
:10118000382F32953F7090E08F7090702A2F229503
:10119000269526952370880F991F880F991F282B55
:1011A000235CAF73A35C10E08B2D86958695835CE2
:1011B000FB01ED50FC4F80838B2D90E0837090708D
:1011C00082959295907F9827807F9827382B335C63
:1011D000FB01EC50FC4F3083FB01EB50FC4F2083B4
:1011E000FB01EA50FC4FA0836C5F7F4F4115510516
:1011F00009F47FCFF701E10FF11DB0801F5F41506F
:10120000504009F095CF002391F0F6013296D601B7
:10121000ED90FC9012E0C12ED12CCE0EDF1E01907D
:10122000F081E02D0150309709F04CC010E030E023
:101230002DE3ADE3B9CF382F32953F7090E08F703A
:1012400090702A2F2295269526952370880F991F36
:10125000880F991F282B235CAF73A35CA5CF0023B5
:1012600071F4382F32953F7090E08F709070880F36
:10127000991F880F991F282F235CADE395CFF601A6
:101280003296D601ED90FC90A2E0CA2ED12CCE0E63
:10129000DF1E4081518101504115510521F0E0E0F0
:1012A000F0E011E054CF382F32953F7090E08F700E
:1012B0009070880F991F880F991F282F235C10E0CA
:1012C000ADE372CFA0E0B0E011E036CF0F931F93F3
:1012D000DF93CF93CDB7DEB760970FB6F894DEBF3C
:1012E0000FBECDBF80910101882309F4ADC080916C
:1012F0003002882329F080910101882309F021C15F
:1013000080913202882329F080910101882309F01D
:1013100042C180913302882329F080910101882302
:1013200009F07CC1609100016F3F09F441C070E099
:1013300062957295707F7627607F76276C577E4F17
:101340008E010F5F1F4FC80140E150E00E943B42F9
:101350008DB79EB70B970FB6F8949EBF0FBE8DBF8B
:10136000EDB7FEB7319681E4ADB7BEB711968C9359
:1013700081E0818382E0828380E091E094838383B3
:1013800081E090E0968385831087078380E190E079
:10139000928781870E945F088FEF809300012DB7AD
:1013A0003EB7255F3F4F0FB6F8943EBF0FBE2DBF2F
:1013B00080918B04882329F080910101882309F012
:1013C00067C18091020190910301892B09F047C008
:1013D00080913402882329F080910101882309F04B
:1013E00022C28091500290915102892B09F0A2C132
:1013F00080913502882329F080910101882309F02A
:10140000A3C180913102882329F0809101018823B2
:1014100009F067C180913702882329F0809101018A
:10142000882309F079C080913602882329F08091C1
:101430000101882309F046C080913802882321F0F9
:10144000809101018823A9F460960FB6F894DEBF5D
:101450000FBECDBFCF91DF911F910F910895809165
:10146000890490918A040E949012882309F0B4CFD5
:10147000AFCF8DB79EB707970FB6F8949EBF0FBE3C
:101480008DBFEDB7FEB7319688E5ADB7BEB7119603
:101490008C9381E08183828387EE92E094838383BF
:1014A00080E190E0968385830E945F081092380265
:1014B0002DB73EB7295F3F4F0FB6F8943EBF0FBE22
:1014C0002DBFC2CF2DB73EB7275030400FB6F8948E
:1014D0003EBF0FBE2DBFEDB7FEB7319680E5ADB76D
:1014E000BEB711968C9381E08183828383E295E07D
:1014F0009483838384E190E0968385830E945F08D0
:10150000109236022DB73EB7295F3F4F0FB6F894C1
:101510003EBF0FBE2DBF90CF00D00F92EDB7FEB7EC
:10152000319684E5ADB7BEB711968C9381E0818387
:1015300012820E945F08109237020F900F900F9056
:1015400072CF2DB73EB7275030400FB6F8943EBF4C
:101550000FBE2DBFEDB7FEB7319686E5ADB7BEB76E
:1015600011968C9381E08183828387EA93E0948350
:1015700083838AE090E0968385830E945F081092BF
:1015800030022DB73EB7295F3F4F0FB6F8943EBFEC
:101590000FBE2DBFB5CE0E9429198DB79EB70B97F0
:1015A0000FB6F8949EBF0FBE8DBFEDB7FEB7319654
:1015B00088E4ADB7BEB711968C9381E0818382E059
:1015C000828389E392E09483838381E090E0968331
:1015D00085838091390224E1829FC00111248D5CB2
:1015E0009E4F9087878384E190E0928781870E9455
:1015F0005F08809139028F5F809339022DB73EB723
:10160000255F3F4F0FB6F8943EBF0FBE2DBF84300D
:1016100010F010923902109232027BCE0E942919EA
:101620008DB79EB70F970FB6F8949EBF0FBE8DBFB4
:10163000EDB7FEB731968CE4ADB7BEB711968C937B
:1016400081E0818383E082838CE792E094838383CB
:1016500021E030E03683258382E391E09087878321
:101660003287218783E391E09487838780E590E048
:10167000968785870E945F08109233022DB73EB788
:10168000215F3F4F0FB6F8943EBF0FBE2DBF4ACE2D
:101690008DB79EB707970FB6F8949EBF0FBE8DBF4C
:1016A000EDB7FEB7319682E4ADB7BEB711968C9315
:1016B00081E0818382838BE894E09483838381E05B
:1016C00090E0968385830E945F0810928B042DB76B
:1016D0003EB7295F3F4F0FB6F8943EBF0FBE2DBFF8
:1016E00070CE8DB79EB707970FB6F8949EBF0FBE0A
:1016F0008DBFEDB7FEB7319687E4ADB7BEB7119693
:101700008C9381E08183828383EC94E09483838350
:101710008BE090E0968385830E945F0810923102EF
:101720002DB73EB7295F3F4F0FB6F8943EBF0FBEAF
:101730002DBF70CE8091A5039091A6030E949012B8
:10174000882309F059CE54CE8DB79EB707970FB6B0
:10175000F8949EBF0FBE8DBFEDB7FEB7319683E400
:10176000ADB7BEB711968C9381E08183828387E900
:1017700093E0948383838EE090E0968385830E9438
:101780005F086091590570915A0580915B059091B1
:101790005C0529E830E040E050E00E9420423093B0
:1017A00098032093970360915D0570915E05809189
:1017B0005F059091600529E830E040E050E00E942C
:1017C000204230939A0320939903609155057091BC
:1017D000560580915705909158052AE030E040E089
:1017E00050E00E94AC412FEA34E040E050E00E941B
:1017F000204230939C0320939B032DB73EB7295F73
:101800003F4F0FB6F8943EBF0FBE2DBF80915002E0
:10181000909151020E9486129093A6038093A50393
:1018200010923502EECD8DB79EB707970FB6F8949C
:101830009EBF0FBE8DBFEDB7FEB7319684E4ADB746
:10184000BEB711968C9381E08183828381EB93E014
:101850009483838382E490E0968385830E945F086B
:101860002DB73EB7295F3F4F0FB6F8943EBF0FBE6E
:101870002DBF80910201909103010E9486129093E6
:101880008A048093890410923402ABCD0F931F9386
:10189000DF93CF9300D0CDB7DEB780913F0288238E
:1018A00019F0815080933F0280913A02882339F4E5
:1018B0000F900F90CF91DF911F910F9108950E948B
:1018C0007007809102038236B9F180910303873655
:1018D00009F46EC1883680F08C3609F443C18D3628
:1018E00008F4C1C0863709F45FC1883709F0BEC06B
:1018F00081E080933802BAC0823609F45DC1833634
:1019000008F4C3C0833609F43BC1843609F0AEC085
:10191000E0913C02F0913D0280812AE0829FC0016B
:1019200011249093030180930201892B09F49EC036
:1019300081E0809334029AC080910303803709F4D8
:1019400062C1813780F58D3609F4D6C08E3609F034
:10195000BCCF809101018823E1F38DB79EB7079733
:101960000FB6F8949EBF0FBE8DBFEDB7FEB7319690
:101970008EE4ADB7BEB711968C9381E081838283EC
:1019800082ED95E0948383838DE490E09683858354
:101990000E945F08EDB7FEB737960FB6F894FEBF0A
:1019A0000FBEEDBF92CF833709F481C0843709F4AD
:1019B0002EC1813709F089CF00913C0210913D0280
:1019C000D8018C918F3F09F456C1D8018C9188239E
:1019D00009F045C181E08C9300913C0210913D02D9
:1019E000D8018C910E948A36E0913C02F0913D0230
:1019F000E0818BE48A83809101018823E1F3E9830C
:101A0000EDB7FEB73F970FB6F894FEBF0FBEEDBF20
:101A1000319681E5ADB7BEB711968C9381E0818395
:101A200083E08283CE0101969483838321E030E0BA
:101A300036832583CE01029690878783328721875C
:101A400085E795E0948783878DE590E09687858785
:101A50000E945F08EDB7FEB73F960FB6F894FEBF41
:101A60000FBEEDBF32CF883609F4B8C010923D02E8
:101A700010923C0210923E0210923A020F900F9088
:101A8000CF91DF911F910F910895813679F7E09101
:101A90003C02F0913D02808180930001803218F079
:101AA0008FE1809300018FEF8093CE04DFCF809190
:101AB000910280FD0ACF00913C0210913D02D801B5
:101AC0008C91882339F08C91863020F411968C917A
:101AD0008B34A9F11982809101018823E1F38DB73C
:101AE0009EB707970FB6F8949EBF0FBE8DBFEDB798
:101AF000FEB7319683E515C0E0913C02F0913D02BE
:101B00008081813009F4C2C019828DB79EB70797D2
:101B10000FB6F8949EBF0FBE8DBFEDB7FEB73196DE
:101B20008DE4ADB7BEB711968C9381E0818382833B
:101B3000CE0101969483838381E090E027CFA5E7CF
:101B4000B5E0F80132968DE501900D928150E1F7F4
:101B5000F80180810E9456360E94E53589830E94F3
:101B6000823DB9CF8FEF8093CE04E0913C02F0919B
:101B70003D02808180937C0281E08093330276CFA6
:101B8000E0913C02F0913D0280812AE0829FC001F9
:101B900011249093510280935002892B09F466CF4F
:101BA00081E08093350262CF81E0809330025ECF86
:101BB00081E0809331025ACFA3ECB4E080913C02E3
:101BC00090913D029C01F9018BE001900D928150B2
:101BD000E1F78091CC0480938B0465CF8FEF8093E5
:101BE000CE04E0913C02F0913D02808190917D0213
:101BF000892B80937D02882311F01092390281E0B5
:101C00008093320233CF81E0809336025ECE8091A2
:101C10003E02853198F0A0E4B2E080913C029091C0
:101C20003D029C01F90180E101900D928150E1F7A4
:101C30008FEF80933F028093CE0447CEE0913C0229
:101C4000F0913D0280819181A281B3818093400215
:101C500090934102A0934202B0934302E9CFF8016E
:101C60008081863008F4BCCE85E0808300913C0200
:101C700010913D02B5CE82E090E00E94CF35F80190
:101C8000808300913C0210913D029FCEA2EDB5E011
:101C90008DE401900D928150E1F70E942F368091E2
:101CA00001018823E1F381E089832FCF982F809170
:101CB0008C04813021F0892F0E94CE0708958091F5
:101CC0007E02E82FF0E0ED5CFE4F90838F5F809303
:101CD0007E0281E008951F93182F181634F480E3D4
:101CE0000E94560E11501116D4F31F9108951F93A0
:101CF000182F181634F480E20E94560E1150111657
:101D0000D4F31F910895EF92FF920F931F93CF93F7
:101D1000DF937C018B016115710569F0C0E0D0E0B3
:101D2000F701EC0FFD1FE4918E2F0E94560E2196B5
:101D3000C017D107A9F7DF91CF911F910F91FF90A5
:101D4000EF9008950F931F93CF93DF938C01EB01D6
:101D50006115710539F0F80181918F010E94560ECD
:101D60002197C9F7DF91CF911F910F9108952F927D
:101D70003F924F925F926F927F928F929F92AF921B
:101D8000BF92CF92DF92EF92FF920F931F93DF9358
:101D9000CF93CDB7DEB7EA970FB6F894DEBF0FBE8C
:101DA000CDBF61962FAD619762963FAD6297609609
:101DB0008FAD609780938C0442E5A42EB12CAC0EBD
:101DC000BD1EC9018C016624772443019E01245D58
:101DD0003F4F3AAF29AFF801F490FF20A9F0F5E2A8
:101DE000FF1691F0680103C0F5E2FF1639F0089480
:101DF000C11CD11CF601F490FF20B1F7B601601BA5
:101E0000710B09F075C08601FF2009F495C20F5FC0
:101E10001F4F1982EE24552444244A94F8010F5F81
:101E20001F4FF490AE2DB0E0A170B07025E7F21610
:101E300009F446C08F2D8062883709F441C06501DE
:101E4000F0E2FF1609F44DC023E2F21609F495C042
:101E50004AE2F41609F495C05DE2F51609F4A0C053
:101E6000FBE2FF1609F441C02EE2F21609F444C069
:101E7000E0E3FE1609F496C08F2D8153893008F0F7
:101E800097C020E030E0C901880F991F880F991F83
:101E9000880F991F220F331F280F391F2F0D311D57
:101EA00020533040F8010F5F1F4FF4908F2D805367
:101EB0008A3048F3522E560125E7F21609F0BACFC0
:101EC000109709F445C094E0C92ED12CCA0CDB1C34
:101ED000F5016080718082809380F0E2FF1609F046
:101EE000B3CF8981882309F046C0F982560196CF85
:101EF000C8010E94830E87CFF8010F5F1F4F949196
:101F00009A3209F45FC0892F80538A3080F5692F97
:101F100020E030E0C901880F991F880F991F880FB2
:101F2000991F220F331F280F391F260F311D2053F1
:101F30003040F8010F5F1F4F6491862F80538A3025
:101F400048F3A90137FD10C0442EF62E5601B4CF38
:101F500082E0C82ED12CCA0CDB1CF5018081918156
:101F60003C01882499246CCF4FEF5FEFEDCFF92E21
:101F700044245601A1CF560151CF38E0E32A56013F
:101F80004DCFA2E0AA2EB12CAC0CBD1CD6015C90AA
:101F900057FE44CF5194B0E1EB2AEFEDEE223ECF55
:101FA0005601F9CFE4FCE7CFF0E2EF2A560136CF35
:101FB00028E6F216B9F04CE6F416C1F451E0E52A31
:101FC00056012CCFF2E0AF2EB12CAC0CBD1CD601CB
:101FD0004D915C9157FD02C0442E20CF4FEF5FEF33
:101FE000442E1CCF34E0E32A560118CF8F2DF60182
:101FF00093E6F91609F405C1843409F472C08436F5
:1020000009F471C0893609F46EC08F3409F47AC1BD
:102010008F3609F474C1803709F479C1B3E7FB1630
:1020200009F430C155E5F51609F4D4C185E7F81671
:1020300009F4CCC1E8E5FE1609F4F8C0F8E7FF168C
:1020400009F4F4C0FF2009F477C1FC8219822E2D17
:1020500030E03DAB2CAB5601EE2434E0232E312C86
:102060002C0E3D1E81E091E0E0E021E0C22ED12C5B
:102070002981222381F18F5F482E4E0E8CA99DA9C4
:102080008073907098AF8FAB892B29F4852D8419BC
:102090000E94770E29812223B9F49CA996FD8CC158
:1020A000EFA9F8ADB09709F482C18E2D0E946B0E96
:1020B000C101B6010E94A20EFCA9F4FF8CCE852DB1
:1020C00084190E94770E87CECE01019661E070E000
:1020D0000E94A20EE5CF5CA956FFCECF892F8E5F5E
:1020E000CBCFB1E0EB2AE0FE54C1B4E0AB2EB12C73
:1020F000AC0CBD1CF601608071808280938097FCDF
:102100003BC1BAE0BEAB47FC02C05FEDE5227CE21A
:10211000272E312C2C0E3D1E611471048104910474
:1021200009F452C09EA9892F90E0A0E0B0E088ABEE
:1021300099ABAAABBBAB6CE2C62ED12CCC0EDD1E8C
:102140006CA67DA68EA69FA62AC050E3352E360E1D
:10215000D6013E926D016CA57DA58EA59FA528A9EF
:1021600039A94AA95BA90E94FE41B901FA01C90136
:10217000DA013C014D012CA53DA54EA55FA588A91E
:1021800099A9AAA9BBA9281739074A075B0708F428
:1021900040C0CB01DF018CA79DA7AEA7BFA76CA550
:1021A0007DA58EA59FA528A939A94AA95BA90E944A
:1021B000FE416A3050F247E5342E360E48E5F416FB
:1021C00039F65FED3522C4CF442089F4AE2DB0E05E
:1021D000BDABACAB80E090E0442DE42EE91AE7FC07
:1021E000C4C0EE2DC82EDD24C7FCD09441CF3EA93B
:1021F000232F30E040E050E028AB39AB4AAB5BAB7B
:102200009ACFA2E0B0E0CA0EDB1E80818C831982D7
:102210001ECF9EA99830D1F0AE2DB0E0BDABACABD7
:10222000B9ADBC198B2F9B2F1601D6CFE3FE1AC078
:102230006114710481049104A9F020E4E22A8F2D35
:1022400030E13EAB1982F82E56015DCFEE2DF0E065
:10225000FDABECABE3FC0AC0F9ADFC198F2F9F2F4F
:102260001601BACF8F2D40E14EABECCF20E33216F2
:1022700009F45CC0F60140E3429389AD8E1B982FB0
:102280001F01AACFF601208031802114310489F486
:10229000F8E2FC832EE62D8335E73E838CE68F83C0
:1022A000888789E289871A86F4E02F2E312C2C0E3C
:1022B0003D1E47FC1CC0442D552747FD5095C101CC
:1022C00060E070E00E944442009719F082194816BD
:1022D0000CF4842DE2E0AE2EB12CAC0CBD1C1982A6
:1022E000982F4E2D50E05DAB4CAB40E076CFF10126
:1022F00001900020E9F731978E2F8219EBCF28E06B
:102300002EABA0CF31E0E32A48E04EAB9BCF82E07A
:1023100090E0C80ED91E808191813C0188249924C7
:1023200090E4E92A88E7A0E1AEAB8CCF39AD3C1947
:10233000832F932F160150CFEA960FB6F894DEBF85
:102340000FBECDBFCF91DF911F910F91FF90EF9006
:10235000DF90CF90BF90AF909F908F907F906F90C5
:102360005F904F903F902F900895C82EDD24C7FCBA
:10237000D094EE24E0E07CCE9094809470946094AD
:10238000611C711C811C911CEDE2E983FAE0FEAB3B
:10239000BACEA2E0AA2EB12CAC0CBD1CD6018D91F8
:1023A0009C913C01882477FC8094982CA8CE852DA4
:1023B00084190E946B0E79CEA0E3AA83FB82CE0122
:1023C000029662E070E00E94A20E6ACE8F2D9AE023
:1023D0009EAB38CFA1E0EA2ABAE0BEAB33CF9FB7BD
:1023E000F8948091DC018A3029F13F9A479884B1B2
:1023F000886184B985B1877E85B984B58F7A84BDBB
:1024000084B5836A84BD85B5877385BD85B5887FAE
:10241000826085BD17BC88E788BD16BC80916E00C0
:10242000897F80936E0080916E00816080936E0042
:102430009FBF0895529A5A98DACF1F920F920FB603
:102440000F9211242F933F938F939F9380915E025D
:10245000882329F080915E02815080935E028091F2
:102460005F02815080935F028F5FA1F489E08093C7
:102470005F028091060191E08927809306018823FD
:10248000F1F1809157029091580201969093580271
:102490008093570280915C0290915D02892BD9F064
:1024A00080915C0290915D02019790935D02809310
:1024B0005C0220915C0230915D0280910401909158
:1024C000050182239323892B61F08091DC018A30FE
:1024D000C9F0479A0BC08FEF9FEF9093050180934F
:1024E00004018091DC018A3079F047989F918F91A7
:1024F0003F912F910F900FBE0F901F9018959093C2
:102500005902BFCF5A9AF2CF5A98F0CF2091570272
:102510003091580221503040280F391FC9010895C9
:102520002091570230915802821B930B8070907853
:10253000892F089520915702309158022150304040
:10254000280F391F8091570290915802A901481B0A
:10255000590BCA01807090789923A1F308952091B6
:1025600057023091580221503040280F391F809176
:10257000570290915802A901481B590BCA0180705B
:102580009078992361F480911601882381F3109249
:10259000160180917A00886C80937A00E8CF0895C4
:1025A0009FB7F894579A5F983E9A469AA0EBB0E08E
:1025B0008C918F708C938C9183608C93E1EBF0E025
:1025C00080818B73808380818B6080831092B200C6
:1025D0008FEF8093B3008C9180688C93E0E7F0E0FC
:1025E00080818A7F80838081826080839FBF0895FD
:1025F00081E080936402089510926402469A0895DF
:102600001F920F920FB60F9211240F900FBE0F90D2
:102610001F9018959FB7F89411B812B88FEF809358
:102620007E00ECE7F0E080818F7180838081807E86
:1026300082608083AAE7B0E087E08C93EBE7F0E06C
:102640008081887F80838C91886C8C939FBF089554
:102650009C01FB018081918182179307ACF0662772
:102660007727621B730B80819181861797074CF047
:102670008081918150E04817590748F011821082FB
:102680000895718360830895318320830895808144
:102690009181841B950B91838083089547B5209188
:1026A0001301249F90011124280F391FC901089597
:1026B0001F920F920FB60F9211248F929F92BF928A
:1026C000CF92DF92EF92FF920F931F932F933F933E
:1026D0004F935F936F937F938F939F93AF93BF932A
:1026E000CF93DF93EF93FF93E0913101F0E02091DE
:1026F000780030917900EE0FFF1FE559FD4F808182
:102700009181820F931F9183808360917B02B62E0B
:10271000B394B0927B026D3009F4B4C16E3008F00E
:1027200042C06B3009F496C16C3008F462C18091EC
:102730002602882309F40BC280910D0190910E01AD
:102740002091790230917A02821B930B90938E0430
:1027500080938D0440916502509166028091A80497
:1027600020918D0430918E046091A80490E001972F
:10277000DC01A49FC001A59F900DB49F900D112472
:10278000820F931F70E00E94EB417093660260938A
:10279000650280918D0490918E046EE974E041E0B1
:1027A0000E942813AFC0613108F0DCC06F3008F41C
:1027B00037C16F50C62FD0E0E2E0F0E0EC1BFD0B1C
:1027C000EE0FFF1FE559FD4F808191816E01CC0C0A
:1027D000DD1CF601EE55FB4F918380832081318112
:1027E00080917D0587FDD5C203E2802E02E0902E08
:1027F0008C0E9D1ED4018C91882309F48CC1F601A6
:10280000E95FFE4F0190F081E02DE21BF30BEE0F2C
:10281000FF1FEE0FFF1FAAEBEA2EA4E0FA2EEC0C2E
:10282000FD1CD7012D913C918091B40490E001975B
:10283000AC01249FC001259F900D349F900D112461
:102840006091B4048E0F9F1F70E00E94EB418B01DA
:10285000CC0FDD1FCD56DB4FCB01BE0145E00E9402
:102860002813F601E656FB4F408151818091B30455
:10287000D7012D913C916091B30490E00197DC0168
:102880004A9FC0014B9F900D5A9F900D1124821BAF
:10289000930B800F911F70E00E94EB417183608366
:1028A000F70111830083F601EE55FB4F2081318142
:1028B000D4018C91882309F421C1F601E95FFE4F10
:1028C00040815181421B530B440F551F440F551F2C
:1028D000F601E755FB4F208131818091B904609169
:1028E000B90490E00197DC012A9FC0012B9F900D55
:1028F0003A9F900D1124840F951F70E00E94EB41C8
:1029000071836083EB2DF0E0EC57FC4FE491E09392
:10291000310180917C00807EE82BE0937C00BB201D
:1029200029F080917A00886C80937A00FF91EF9172
:10293000DF91CF91BF91AF919F918F917F916F91D7
:102940005F914F913F912F911F910F91FF90EF90C9
:10295000DF90CF90BF909F908F900F900FBE0F9001
:102960001F901895613171F68091140190911501B5
:102970009C01220F331F280F391F80917302909101
:10298000740263E070E00E94D741260F371F36952E
:102990002795369527953093150120931401809142
:1029A0001401909115019093CA038093C90381E0AB
:1029B000809316018091690290916A02019690932A
:1029C0006A028093690210927B02EBE6F2E01192B8
:1029D0001192B2E0EB37FB07D1F7E4E8F3E0E491C2
:1029E000E093310180917C00807EE82BE0937C00B5
:1029F0009DCF683009F086CF80912802882309F4A2
:102A0000B5C0809111019091120120917502309111
:102A10007602821B930B909392048093910472CF61
:102A200080912F0190913001009709F4AEC0019779
:102A30009093300180932F0187B58093E903109222
:102A4000EA038091B1049091B2049093F2038093D1
:102A5000F10358CF20916B0230916C023093A704A0
:102A60002093A60480912502882309F467C18091F0
:102A70000B0190910C01821B930B9093980480930F
:102A8000970440CF80912702882309F451C0809198
:102A90000F01909110012091770230917802821BF2
:102AA000930B9093900480938F0440916702509110
:102AB00068028091A80420918F0430919004609165
:102AC000A80490E00197FC01E49FC001E59F900DF0
:102AD000F49F900D1124820F931F70E00E94EB4130
:102AE000709368026093670280918F0490919004C4
:102AF00060EA74E041E00E94281304CFF601E95F28
:102B0000FE4F80819181A901481B590B440F551F2D
:102B1000440F551FDDCEF601E95FFE4F80819181A4
:102B2000F901E81BF90BEE0FFF1FEE0FFF1F73CE2D
:102B300020910F01309110018091770290917802DD
:102B4000821B930B9093900480938F04AECF2091BF
:102B50000D0130910E018091790290917A02821BD1
:102B6000930B90938E0480938D04F4CD20911101EA
:102B7000309112018091750290917602821B930B25
:102B80009093920480939104BDCEE0917102F091F4
:102B9000720221E0E039F20708F4DBC036E0EF36DC
:102BA000F307D8F027B56091130170E0660F771F27
:102BB000660F771F8EED94E00E94EB41620F711D4E
:102BC000603F71050CF063C187B5AB01481B51092B
:102BD0005093300140932F0167BD27B580911301B9
:102BE000829FC00111248E0F9F1F9093B204809387
:102BF000B10487B58093E9031092EA038091B10490
:102C00009091B2049093F2038093F10380911301A9
:102C10002091B1043091B2046FE0869FC00111246D
:102C20002817390708F0C5C0E0901301209113015F
:102C30004091B1045091B2048091AD049091AE04E2
:102C4000A091AF04B091B004E69E7001112400275A
:102C5000F7FC0095102FE80EF91E0A1F1B1F30E02D
:102C600081EF9FEF289FB001299F700D389F700D55
:102C70001124640F751F80E090E029E130E040E00E
:102C800050E00E94AC41E60EF71E081F191FE092AB
:102C9000AD04F092AE040093AF041093B0048091A1
:102CA00099048E5F8093990480919904803108F48F
:102CB00029CEE090B504F090B6040091B7041091CD
:102CC000B8046091AD047091AE048091AF0490910E
:102CD000B0046C5F7F4F8F4F9F4FA8019701220F69
:102CE000331F441F551F220F331F441F551F220F30
:102CF000331F441F551F2E193F09400B510B620F04
:102D0000731F841F951F28E030E040E050E00E94D0
:102D10002042C901DA018093B5049093B604A093D0
:102D2000B704B093B8041092AD041092AE041092A0
:102D3000AF041092B00410929904E4CD80910B017D
:102D400090910C01281B390B309398042093970421
:102D5000D9CD27B580911301682F70E0660F771FDA
:102D6000660F771F709561957F4F8EED94E00E94FE
:102D7000EB41620F711D603171050CF45BC087B5CA
:102D800090E0861B970B9093300180932F0167BDD5
:102D900024CF20323105D4F58EE490E0D901A89FEC
:102DA0009001A99F300DB89F300D1124245C39404B
:102DB0001BCD809113012091B1043091B20460EFDA
:102DC000869FC00111248217930708F041C0E0904C
:102DD0001301209113014091B1045091B2048091EC
:102DE000AD049091AE04A091AF04B091B004E69E02
:102DF000700111240027F7FC0095102FE80EF91E32
:102E00000A1F1B1F30E080E19FEF2CCFBFE02D3D5C
:102E10003B070CF4E9CC2C5D3F408EE490E0F901D7
:102E2000E89F9001E99F300DF89F300D1124245246
:102E3000304FDACC87B5882309F4CFCE87B58150DF
:102E400087BD81E090E09093300180932F01C5CE43
:102E5000809199048F3049F18091B1049091B2042E
:102E60002091AD043091AE044091AF045091B00474
:102E7000A0E0B0E0820F931FA41FB51F8093AD04A4
:102E80009093AE04A093AF04B093B00408CF87B57D
:102E90008E3F08F0A2CE87B58F5F87BD81E090E0BE
:102EA0009093300180932F0198CE8091B10490913E
:102EB000B2042091AD043091AE044091AF04509122
:102EC000B00496958795A0E0B0E0820F931FA41FF1
:102ED000B51F8093AD049093AE04A093AF04B0935C
:102EE000B004DDCEEF92FF920F931F93DF93CF9349
:102EF000CDB7DEB72C970FB6F894DEBF0FBECDBFAF
:102F00007E010894E11CF11CD701E7E1F1E08CE0BF
:102F100001900D928150E1F710E08AE090E00E946C
:102F2000AF1220918D0430918E04442737FD4095D7
:102F3000542F89819A81AB81BC81820F931FA41F7A
:102F4000B51F89839A83AB83BC8320918F04309112
:102F50009004442737FD4095542F8D819E81AF8189
:102F6000B885820F931FA41FB51F8D839E83AF83E7
:102F7000B8872091910430919204442737FD409501
:102F8000542F89859A85AB85BC85820F931FA41F1A
:102F9000B51F89879A87AB87BC871F5F1A3009F0F6
:102FA000BCCF00E010E0F7016081718182819381E4
:102FB0006B5F7F4F8F4F9F4F2AE030E040E050E043
:102FC0000E942042D801AA0FBB1FFD01E35FFE4F04
:102FD00040815181F801EA5DFD4F8081882319F01D
:102FE000309521953F4F240F351FA35FBE4F11969B
:102FF0003C932E930F5F1F4F84E090E0E80EF91E84
:103000000330110581F660910D0170910E010E944F
:10301000513660910F017091100186E090E00E949E
:103020005136609111017091120188E090E00E9488
:1030300051361092A1041092A0048091A0049091A6
:10304000A10490939F0480939E0484E690E00E94E4
:10305000AF122C960FB6F894DEBF0FBECDBFCF9146
:10306000DF911F910F91FF90EF900895CF92DF9223
:10307000EF92FF920F931F93DF93CF93CDB7DEB7FD
:103080002C970FB6F894DEBF0FBECDBF7E0108941B
:10309000E11CF11CD701E3E2F1E08CE001900D921C
:1030A0008150E1F74091C301842F83708F5F80933B
:1030B000B404242F30E0C9018C70907095958795E9
:1030C000959587958F5F8093B904207330703595FF
:1030D00027953595279535952795359527952F5F14
:1030E0002093B30442954695469543704F5F4093B5
:1030F000A8040E948D3E10E084E190E00E94AF128F
:103100002091A2043091A304442737FD4095542F09
:1031100089819A81AB81BC81820F931FA41FB51F47
:1031200089839A83AB83BC832091A4043091A50446
:10313000442737FD4095542F8D819E81AF81B885FE
:10314000820F931FA41FB51F8D839E83AF83B88703
:103150002091A6043091A704442737FD4095542FB1
:1031600089859A85AB85BC85820F931FA41FB51FE7
:1031700089879A87AB87BC871F5F103209F0BCCF65
:1031800067012BEDE22E23E0F22E00E010E0F601C5
:1031900061917191819191916F01605F7F4F8F4F2C
:1031A0009F4F20E230E040E050E00E942042F801D2
:1031B000EE0FFF1FE95FFE4F3183208380819181F5
:1031C000F701819391937F010F5F1F4F033011052A
:1031D000F1F61092960410929504809195049091C6
:1031E0009604909394048093930484E090E00E946A
:1031F000AA3690930E0180930D0186E090E00E9424
:10320000AA369093100180930F0188E090E00E940D
:10321000AA36909312018093110184E690E00E94F7
:10322000AF122C960FB6F894DEBF0FBECDBFCF9174
:10323000DF911F910F91FF90EF90DF90CF90089555
:10324000E3E3F1E080E2819391E0E338F907D9F715
:103250000895FF920F931F9380917D0290E080FF6D
:1032600008C020917C02222309F40DC12150209333
:103270007C023091320181FF08C020917C0223172B
:1032800009F406C12F5F20937C028370907003972E
:1032900011F410927C02E3E3F1E080E2819321E0FB
:1032A000E338F207D9F720917C02321718F43093F3
:1032B0007C02232F2A30C8F581E180937E0200D062
:1032C00000D00F92EDB7FEB7319681E0ADB7BEB733
:1032D00011968C938AE396E09283818323831482F0
:1032E0000E94B70E0F900F900F900F900F9080914B
:1032F0007C02873009F430C3883040F18B3009F408
:10330000F8C38C3008F0C7C0883009F4E2C48930B3
:1033100009F460C481508093320110927C021092B3
:103320007D021F910F91FF90089580E180937E02AE
:1033300000D000D00F92EDB7FEB7319681E0ADB767
:10334000BEB711968C9385E396E0C6CF823009F420
:1033500083C2833008F050C18823E1F610927E02C8
:1033600000D00F9211E0EDB7FEB7118385E296E031
:10337000938382830E94B70E84E180937E02209122
:10338000DC018DB79EB70A970FB6F8949EBF0FBEAB
:103390008DBFEDB7FEB73196ADB7BEB711961C9392
:1033A00080E196E092838183822F6AE00E94CB4184
:1033B00083831482822F0E94CB41958316821086CC
:1033C00017828AE490E09287818785EC90E0948769
:1033D00083870E94B70E88E280937E02EDB7FEB726
:1033E0003D960FB6F894FEBF0FBEEDBF0E94E535C7
:1033F0002DB73EB7275030400FB6F8943EBF0FBEF2
:103400002DBFEDB7FEB73196ADB7BEB711961C9381
:1034100021E036E0328321838383148283ED95E0BB
:10342000968385830E94B70E8091830190918401D9
:10343000EDB7FEB737960FB6F894FEBF0FBEEDBFDF
:10344000069708F4AFC420919602222309F498C489
:103450008CE380937E0200D000D00F92EDB7FEB7D0
:103460003196ADB7BEB711961C9381EE95E092836D
:103470008183238314820E94B70E0F900F900F90C8
:103480000F900F904CCF3091320130937C02F3CEED
:1034900010927C02FACE8C3009F45DC18D3009F0B7
:1034A00039CF10927E0200D00F9211E0ADB7BEB7B7
:1034B00011961C93119788ED93E013969C938E932D
:1034C00012970E94B70E84E180937E02EDB7FEB79B
:1034D00038970FB6F894FEBF0FBEEDBF3196ADB76B
:1034E000BEB711961C9384EC93E092838183809104
:1034F000E00490E08D96948383838091E50490E0CE
:103500008D96968385838091EA0490E08D969087CE
:1035100087838091EF0490E08D96928781870E9447
:10352000B70E88E280937E02EDB7FEB73196ADB755
:10353000BEB711961C9380EB93E0928381838091B8
:10354000F40490E08D96948383838091F90490E055
:103550008D96968385838091FE0490E08D9690876A
:1035600087838091030590E08D96928781870E94E2
:10357000B70E8CE380937E02EDB7FEB736960FB69A
:10358000F894FEBF0FBEEDBF3196ADB7BEB7119632
:103590001C938FE993E0928381838091080590E0EA
:1035A0008D96948383830E94B70E0F900F900F9097
:1035B0000F900F9080910D05882309F020C4809111
:1035C0001205882309F004C480911705882309F4A3
:1035D000A6CE88E480937E0200D00F9281E0EDB702
:1035E000FEB7818386E993E0938382830E94B70EBE
:1035F0000F900F900F9093CE833009F4FBC184306D
:1036000009F088CE10927E02E0917505F0E0EE0F91
:10361000FF1FED5DFA4F40815181E0917605F0E0AA
:10362000EE0FFF1FED5DFA4F208131818DB79EB700
:1036300007970FB6F8949EBF0FBE8DBFEDB7FEB7CC
:10364000319611E0ADB7BEB711961C938BE495E0AF
:103650009283818354834383368325830E94B70EEC
:1036600084E180937E02E0917705F0E0EE0FFF1F8A
:10367000ED5DFA4F40815181E0917805F0E0EE0F69
:10368000FF1FED5DFA4F20813181EDB7FEB7319616
:10369000ADB7BEB711961C938BE395E092838183FF
:1036A00054834383368325830E94B70E88E2809338
:1036B0007E02E0917905F0E0EE0FFF1FED5DFA4F1D
:1036C00040815181E0917A05F0E0EE0FFF1FED5D42
:1036D000FA4F20813181EDB7FEB73196ADB7BEB755
:1036E00011961C938BE295E09283818354834383EC
:1036F000368325830E94B70E8CE380937E02E0918F
:103700007B05F0E0EE0FFF1FED5DFA4F4081518128
:10371000E0917C05F0E0EE0FFF1FED5DFA4F208198
:103720003181EDB7FEB73196ADB7BEB711961C9398
:103730008BE195E092838183548343833683258391
:103740000E94B70EEDB7FEB737960FB6F894FEBFDE
:103750000FBEEDBFE4CD10927E0200D00F9211E0BB
:10376000ADB7BEB711961C93119786E294E01396FD
:103770009C938E9312970E94B70E84E180937E02F1
:10378000EDB7FEB738970FB6F894FEBF0FBEEDBF8A
:103790003196ADB7BEB711961C9381E194E0928348
:1037A00081838091E104838314828091E604858380
:1037B00016828091EB04878310868091F0048187C4
:1037C00012860E94B70E88E280937E02EDB7FEB7A4
:1037D0003196ADB7BEB711961C938CEF93E09283F0
:1037E00081838091F504838314828091FA04858318
:1037F00016828091FF04878310868091040581875B
:1038000012860E94B70E8CE380937E02EDB7FEB75E
:103810003196ADB7BEB711961C9387EE93E09283B5
:103820008183809109058383148280910E058583AD
:1038300016828091130587831086809118058187F1
:1038400012860E94B70EEDB7FEB73B960FB6F894FE
:10385000FEBF0FBEEDBF63CD10927E0200D00F926F
:10386000FF24F394ADB7BEB71196FC92119788EC84
:1038700095E013969C938E9312970E94B70E84E165
:1038800080937E0200D000D00DB71EB70F5F1F4F90
:10389000EDB7FEB7F18289EB95E0D80112969C93C3
:1038A0008E9311976091590570915A0580915B052F
:1038B00090915C052AE535E040E050E00E9420420E
:1038C000F80123833483458356830E94B70E88E230
:1038D00080937E020DB71EB70F5F1F4FADB7BEB707
:1038E0001196FC928AEA95E0F801928381836091B7
:1038F0005D0570915E0580915F05909160052AE5F8
:1039000035E040E050E00E942042D80113962D930C
:103910003D934D935C9316970E94B70E8CE3809372
:103920007E020F900F90EDB7FEB73196ADB7BEB7E0
:103930001196FC928BE995E09283818380918701B7
:1039400090918801948383830E94B70E0F900F900B
:103950000F900F900F90E3CC84E180937E028091D2
:1039600014019091150100911401109115012DB7CA
:103970003EB7275030400FB6F8943EBF0FBE2DBF64
:10398000EDB7FEB73196FF24F394ADB7BEB71196ED
:10399000FC9228E035E0328321836AE070E00E94E7
:1039A000EB4174836383C8016AE070E00E94EB41DD
:1039B000968385830E94B70E88E280937E022091D1
:1039C000990230919A020F900F90EDB7FEB73196A1
:1039D000ADB7BEB71196FC928AEF94E092838183D3
:1039E000348323830E94B70E0F900F900F900F9097
:1039F0000F9095CC10927E022091250530912605DE
:103A00004091270550912805EDB7FEB737970FB6BF
:103A1000F894FEBF0FBEEDBF319611E0ADB7BEB753
:103A200011961C938BE895E09283818334832383E2
:103A3000568345830E94B70E84E180937E022091D5
:103A4000290530912A0540912B0550912C05EDB7A1
:103A5000FEB73196ADB7BEB711961C938BE795E0D4
:103A60009283818334832383568345830E94B70ED8
:103A700088E280937E0220912D0530912E054091A1
:103A80002F0550913005EDB7FEB73196ADB7BEB7F3
:103A900011961C938BE695E0928381833483238374
:103AA000568345830E94B70E8CE380937E0220915B
:103AB0003105309132054091330550913405EDB711
:103AC000FEB73196ADB7BEB711961C938BE595E066
:103AD0009283818334832383568345830E94B70E68
:103AE000EDB7FEB737960FB6F894FEBF0FBEEDBF29
:103AF00016CC10927E0200D00F9211E0ADB7BEB787
:103B000011961C93119786E694E013969C938E93DE
:103B100012970E94B70E84E180937E0200D000D0FD
:103B2000EDB7FEB73196ADB7BEB711961C9386E5DB
:103B300094E0928381838091C604992787FD9095B4
:103B4000948383838091C704992787FD90959683FA
:103B500085830E94B70E88E280937E02EDB7FEB7A0
:103B60003196ADB7BEB711961C9386E494E092836C
:103B700081838091C904838314828091C80499272A
:103B800087FD9095968385830E94B70E8CE3809382
:103B90007E02EDB7FEB73196ADB7BEB711961C9356
:103BA00086E394E0928381838091CA04992787FDFC
:103BB0009095948383838091CD04858316820E949F
:103BC000B70EEDB7FEB737960FB6F894FEBF0FBE2F
:103BD000EDBFA5CB10927E02EDB7FEB737970FB6BB
:103BE000F894FEBF0FBEEDBF319611E0ADB7BEB782
:103BF00011961C938CEA94E0928381838091E70272
:103C00009091E802948383838091EF029091F00277
:103C1000968385830E94B70E84E180937E02EDB780
:103C2000FEB73196ADB7BEB711961C938AE994E002
:103C3000928381838091E9029091EA029483838345
:103C40008091F1029091F202968385830E94B70ED3
:103C500088E280937E02EDB7FEB73196ADB7BEB76E
:103C600011961C9388E894E0928381838091EB0203
:103C70009091EC02948383838091F3029091F402FB
:103C8000968385830E94B70E8CE380937E02EDB706
:103C9000FEB73196ADB7BEB711961C9386E794E098
:103CA000928381838091ED029091EE0294838383CD
:103CB0008091F5029091F602968385830E94B70E5B
:103CC000EDB7FEB737960FB6F894FEBF0FBEEDBF47
:103CD00026CB10927E0200D00F9211E0EDB7FEB716
:103CE00011838BEE94E0938382830E94B70E84E16C
:103CF00080937E0200D0EDB7FEB73196ADB7BEB768
:103D000011961C938CED94E09283818380918901BC
:103D100090918A01948383830E94B70E88E28093F6
:103D20007E02EDB7FEB73196ADB7BEB711961C93C4
:103D30008DEC94E09283818380918701909188013A
:103D4000948383830E94B70E8CE380937E02EDB749
:103D5000FEB73196ADB7BEB711961C938EEB94E0CB
:103D6000928381838091A3029091A40294838383A0
:103D70000E94B70E0F900F900F900F900F90CFCA28
:103D80008CE380937E0200D00F92EDB7FEB71183D3
:103D900081ED95E0938382830E94B70E0F900F9080
:103DA0000F90BDCA8CE380937E0200D00F92ADB716
:103DB000BEB711961C93119784EF95E013969C93D0
:103DC0008E9312970E94B70E0F900F900F90A7CA74
:103DD00084E480937E0200D00F9281E0ADB7BEB73D
:103DE00011968C93119789E993E013969C938E9387
:103DF00012970E94B70E0F900F900F90E5CB80E4C2
:103E000080937E0200D00F92EDB7FEB711838CE94C
:103E100093E0938382830E94B70E0F900F900F90D0
:103E2000CECB87B18C6087B9429843981092C10479
:103E30001092C00480E88093BF048093BE0408956C
:103E4000382F6B3F20F0273E28F52A3088F1A32F2A
:103E5000B0E0FD01E054FB4F8081815080838F5F93
:103E6000C1F461506083FD01E254FB4F80818130D9
:103E7000B9F1869580838081842339F528B184E067
:103E800090E002C0880F991FAA95E2F780958223DF
:103E900088B9089547FD0EC028B184E090E002C0C3
:103EA000880F991F3A95E2F78095822388B9089583
:103EB00047FDF2CF28B184E090E002C0880F991F3F
:103EC0003A95E2F7282B28B9089528B184E090E0CC
:103ED00002C0880F991FAA95E2F7282B28B90895E8
:103EE00080E88083C8CF80917F02815080937F02D9
:103EF0008F5F09F0089584E080937F0280E06091F5
:103F0000AC054091AB052091CE010E94201F81E0BD
:103F10006091AE054091AD052091CF010E94201F18
:103F200008950E94731F08958091C204089580919E
:103F30008D02089580918E0208950E94632808954D
:103F40001F930E944B27182F0E947121811708F49C
:103F5000812F1F9108951F93CF93DF93C7EED2E077
:103F600010E00BC02F3F310594F42F5F3F4F398392
:103F700028831F5F22961830C1F0812F0E942B27C3
:103F800097FD17C028813981281739075CF312166D
:103F900013067CF78217930764F72150304039836A
:103FA00028831F5F2296183041F7DF91CF911F9130
:103FB000089580E090E0E6CFEF92FF920F931F9379
:103FC000CF93DF930E941E260E9424210E948638F0
:103FD0000E9428277C010E9418218C01FC0180810D
:103FE0009181F70120813181820F931F9093850287
:103FF00080938402F80182819381F70122813381C9
:10400000820F931F9093870280938602F801848128
:104010009581F70124813581820F931F0E94A43D71
:104020000E945C3990938B0280938A02F80186810A
:104030009781F70126813781820F931F9093890220
:104040008093880280918402909185029093CC03A2
:104050008093CB0380918602909187029093CE0348
:104060008093CD030E94A01F843008F08EC0109270
:104070008C02E4E8F2E0A0E8B2E0C4E6D0E06081BF
:1040800071814D915C911197CB019C0197FD7AC094
:10409000359527953595279537FD70C042175307FD
:1040A00008F03FC09B0177FD92C0C90195958795A7
:1040B0009595879511969C938E938536910518F06A
:1040C0001196DC93CE933296129682E0E838F80788
:1040D000B1F60E944B27833008F075C000E00E94C3
:1040E0007121833008F05CC090E0002309F05EC0CD
:1040F000992301F510928E0210928D028091B103E6
:104100008F7E8093B103002369F58091B2038F7E87
:104110008093B203DF91CF911F910F91FF90EF90A9
:1041200008954115510579F24150504011965C9324
:104130004E93C9CF10928E0280918D02981709F488
:104140004AC090938D020E941B218093C2048091EB
:104150008E02882399F28091B10380618093B1032C
:10416000002399F28091B20380618093B203DF91C2
:10417000CF911F910F91FF90EF9008953095219569
:104180003F4F8CCF2D5F3F4F83CF0E94AB1F0E94CC
:10419000603A80918C020E94CC2780938C0269CF78
:1041A0000E941E21982F002309F4A2CF10928E02A4
:1041B00080918D02081799F000938D020E9472275A
:1041C0008093C204C4CF0E946927082F88CF3095FE
:1041D00021953F4F6ACF81E080938E02B2CF81E07C
:1041E00080938E02E9CF1F93CF93DF93C7EED2E087
:1041F00010E0812F0E942B27899399931F5F18301D
:10420000C1F7DF91CF911F9108950E940A210E946A
:10421000513808951092CD041092C6041092C7042C
:104220001092C8041092C90485E58093C3040895D0
:104230008FEC94E008958091CD0408958091CB0493
:10424000089580E090E008958091CE04882389F459
:104250001092D6041092D5041092D4041092D30474
:104260001092D2041092D1041092D0041092CF0474
:10427000089581508093CE042091840530E0809190
:10428000C604992787FD9095AC01249FC001259F06
:10429000900D349F900D11249093D0048093CF04FF
:1042A0008091C704992787FD9095AC01429FC0017A
:1042B000439F900D529F900D11249093D2048093B0
:1042C000D1048091C9048093D3041092D4048091C6
:1042D000C804992787FD90959093D6048093D504C0
:1042E00008958091CE04813580F4882359F480911B
:1042F000CD0480FF0DC090E08091CD01813818F091
:1043000091E001C093E0892F089594E0892F0895EA
:1043100090E0892F08951092D8041092D70410923B
:10432000DA041092D9040895EF92FF920F931F932D
:104330002AE535E040E050E00E942042CA01B90180
:1043400028E631E040E050E00E942042AC01CB0181
:10435000DA019C01AD0157FD25C061E02A35310528
:104360004105510564F084EB90E0A0E0B0E07C01F1
:104370008D01E21AF30A040B150BA8019701E22F35
:10438000F0E0EE0FFF1FE15CF94F259134916130B1
:1043900019F0309521953F4FC9011F910F91FF9062
:1043A000EF90089550954095309521953F4F4F4F90
:1043B0005F4F6FEFD3CF653A21EE720721E082079E
:1043C00020E092073CF46C557E418E4F9F4F0E9437
:1043D000942108956C5E744A854090400E94942117
:1043E00008952AE535E040E050E00E942042C901EE
:1043F000DA019C01AD018A359105A105B105B4F042
:1044000024EB30E040E050E0281B390B4A0B5B0BFB
:10441000E22FF0E0EE0FFF1FEB50F94F85919491E2
:1044200022273327281B390BC9010895263A6FEF3D
:1044300036076FEF46076FEF560774F42C543F4F63
:104440004F4F5F4FE22FF0E0EE0FFF1FEB50F94FA1
:1044500025913491C9010895B7FFF4CF222733275E
:10446000A901281B390B4A0B5B0BD2CF9FB7F894DD
:104470003998389A88B1836088B98091B9008C7F67
:104480008093B9008AE28093B80010929202109251
:10449000940210929502EFEDF4E0108211821282E4
:1044A0001482359685E0EB31F807B9F79FBF089580
:1044B0008093920285EA8093BC00089580939202D3
:1044C00084E98093BC0008958093BB0085E88093C5
:1044D000BC00089585EC8093BC00089585E8809326
:1044E000BC0008950F931F93109292020CEB10E002
:1044F00084E9D8018C9310929202EBEBF0E080817A
:1045000080939402109294021092950280E88C930A
:104510001092BD001092BA0010821092B900109251
:10452000B8000E9436221092920285EAF801808338
:104530001F910F9108951F920F920FB60F921124A1
:104540002F938F939F93EF93FF93809192028F5FAE
:10455000809392028150853009F4C3C0863020F1E7
:10456000893009F497C08A30E0F5873009F411C129
:10457000883009F404C11092920284E98093BC004F
:104580008AE090E0909384018093830110929402DA
:1045900010929502FF91EF919F918F912F910F9023
:1045A0000FBE0F901F901895823009F47FC08330A2
:1045B00080F1833009F4BCC08430E9F68091950223
:1045C0002091BB0090E0FC01EE0FFF1FEE0FFF1FDC
:1045D000E80FF91FE152FB4F238385E88093BC006D
:1045E000D9CF8A3009F49DC08B3029F610929202FF
:1045F00084E98093BC008AE090E0909384018093EA
:10460000830180919702823008F417C110929702BB
:10461000C1CF8823F9F0813009F0ADCF80919402A9
:1046200090E0FC01EE0FFF1FEE0FFF1FE80FF91FD8
:10463000E152FB4F80818093BB0085E88093BC00F2
:10464000A9CF809194028C3088F4809194028F5F7E
:1046500080939402E0919402F0E0EE0FFF1FEE0FC2
:10466000FF1FEE52FA4F858518165CF78091940271
:104670008C3008F495C01092940283E080939202EB
:1046800080919502880F8D5A8093BB0085E88093B6
:10469000BC0080CFE0919702F0E0E552FB4F8081B3
:1046A0008093BB0085E88093BC0074CF8091B900F3
:1046B000803309F484C01092920284E98093BC0094
:1046C0008AE090E09093840180938301809194022A
:1046D0008F5F809394021092920285EA8093BC00CF
:1046E00059CF809195022091BB0090E0FC01EE0F24
:1046F000FF1FEE0FFF1FE80FF91FE152FB4F24834E
:10470000809195028F5F80939502809195028C3005
:1047100010F0109295021092920284E98093BC00EE
:1047200039CF80E88093BB0085E88093BC0032CF0E
:104730008091B900803409F46CC08091950290E0BA
:10474000FC01EE0FFF1FEE0FFF1FE80FF91FE152F4
:10475000FB4F1182809195028F5F8093950280912B
:1047600095028C3048F51092920284E98093BC0047
:104770008091980280939602109298020BCF8091BC
:104780009702880F805F8093BB0085E88093BC0010
:1047900001CF88E98093BB0085E88093BC00FACE06
:1047A0008091940290E08996880F991F8093BB00B6
:1047B00085E88093BC00EECE10929502D4CF809114
:1047C0009802882329F4809194028F5F8093980245
:1047D0008091940290E0FC01EE0FFF1FEE0FFF1F8F
:1047E000E80FF91FE152FB4F82818F5F828388239C
:1047F00009F061CF8091940290E0FC01EE0FFF1F61
:10480000EE0FFF1FE80FF91FE152FB4F8FEF82837E
:1048100052CF809195022091950290E0FC01EE0F1D
:10482000FF1FEE0FFF1FE80FF91FE152FB4F2C5F38
:10483000218385EC8093BC009BCF8F5F8093970290
:1048400087E08093920285EA8093BC00A3CE8F928A
:104850009F92BF92CF92DF92EF92FF920F931F939E
:10486000CF93DF9300D00F92ADB7BEB711961C92D5
:1048700011978DEC97E013969C938E9312970E945C
:10488000B70EEFEDF4E00F900F900F901082359679
:10489000B5E0EB31FB07D1F71092920285EA8093E5
:1048A000BC0080E197E20197F1F7109295028F0129
:1048B0000B531040E80161E0E62EF12C55EAB52ECD
:1048C00040E1C42E47E2D42E39EC832E37E0932EFC
:1048D00008C025960894E11CF11CB5E0CC31DB073B
:1048E00039F110929202B092BC00C6010197F1F723
:1048F0008881882371F300D000D00F92EDB7FEB706
:104900003196ADB7BEB711961C9292828182F48225
:10491000E3820E94B70E0F900F900F900F900F90B0
:1049200025960894E11CF11CB5E0CC31DB07C9F6F3
:10493000CFEDD5E021E0E22EF12C9BEAC92E97E0E5
:10494000D92EF80180818823C1F488811816ACF42F
:1049500000D000D00F92EDB7FEB73196ADB7BEB71D
:1049600011961C92D282C182F482E3820E94B70E19
:104970000F900F900F900F900F90F80111820B5F26
:104980001F4F24960894E11CF11CF5E00C311F0721
:10499000C1F6DF91CF911F910F91FF90EF90DF90C3
:1049A000CF90BF909F908F9008959FB7F89456989E
:1049B0005E9A8AB188638AB98BB1877C8BB9809102
:1049C000F702813011F0539A5B98809180008C70CF
:1049D0008093800080918100837E8093810080910C
:1049E0008100836C80938100809182008F7380931B
:1049F000820080916F00887F80936F0080916F00AC
:104A0000806280936F0010929A02109299029FBF69
:104A100008951F920F920FB60F9211240F931F93B8
:104A20002F933F934F935F936F937F938F939F93B6
:104A3000AF93BF93CF93DF93EF93FF9320918600C3
:104A40003091870080919D0290919E02281B390B26
:104A5000809186009091870090939E0280939D02A2
:104A6000C9018D549440835F9A4118F580919F024B
:104A70009091A002049714F01092850181E090E0DB
:104A80009093A00280939F02FF91EF91DF91CF91CD
:104A9000BF91AF919F918F917F916F915F914F9156
:104AA0003F912F911F910F910F900FBE0F901F906C
:104AB0001895C0919F02D091A002C930D10524F76A
:104AC000C9018B5F9040845B914008F055C0265D22
:104AD00031408E01000F111FF801ED5DFA4F80810A
:104AE0009181F901E81BF90BCF01F7FD60C0069732
:104AF0008CF48091990290919A02883C91050CF077
:104B00004FC08091990290919A020A9690939A02CE
:104B100080939902F801ED5DFA4F808191810197B0
:104B20002817390734F08081918101968217930705
:104B30007CF58091990290919A02833C910514F141
:104B4000F801ED5DFA4F80819181A901481B590B55
:104B5000CA0163E070E00E94EB41CB01880F991F0E
:104B6000860F971FF801E95CFA4F918380830D5DF2
:104B70001A4FF801318320832196D093A002C0936D
:104B80009F0282CFF801E95CFA4F11821082EFCFC9
:104B90002F5F3F4F2330310570F420E030E0C9CF64
:104BA00088EC90E090939A0280939902B3CF90950D
:104BB00081959F4F9CCF20813181BBCF809177051C
:104BC000E82FF0E0EE0FFF1FED5DFA4F808191813D
:104BD00086359105C4F080917805E82FF0E0EE0F5E
:104BE000FF1FED5DFA4F80819181863591053CF480
:104BF000808191818B5A9F4F24F484E0089582E054
:104C0000089580E00895808191818B5A9F4FCCF761
:104C100080917805E82FF0E0EE0FFF1FED5DFA4F71
:104C200080819181863591053CF4808191818B5AF8
:104C30009F4F3CF786E0089588E008951F93CF9337
:104C4000DF938091990290919A02892B09F4D7C041
:104C50008091990290919A02019790939A02809381
:104C60009902809185018150809385018F5F09F0C1
:104C7000B7C0E0917505F0E0EE0FFF1FDF01AD5DFD
:104C8000BA4F2D913C916091840570E0E95CFA4F38
:104C9000808191814091850550E0FC01E49FC00135
:104CA000E59F900DF49F900D1124F901E69F90016E
:104CB000E79F300DF69F300D1124820F931F9093C4
:104CC0001C0580931B05E0917605F0E0EE0FFF1FB9
:104CD000DF01AD5DBA4F2D913C91E95CFA4F8081C7
:104CE0009181FC01E49FC001E59F900DF49F900D20
:104CF0001124A901469F9001479F300D569F300D0A
:104D00001124820F931F90931E0580931D05E0913F
:104D10007705F0E0EE0FFF1FDF01AD5DBA4F2D917B
:104D20003C91E95CFA4F4081518128583F4F809176
:104D3000C20190E0BC01469FC001479F900D569F65
:104D4000900D1124280F391F3093200520931F0543
:104D500037FD71C0E0917805F0E0EE0FFF1FDF0135
:104D6000AD5DBA4F2D913C91E95CFA4F8081918104
:104D7000CC27DD27C21BD30BC81BD90B109186058E
:104D8000BE01882777FD8095982F212F30E040E0E5
:104D900050E00E94AC41FE01D7FD55C09F01442761
:104DA00037FD4095542F0E94AC4120E032E040E0B6
:104DB00050E00E942042812F90E0C89FB001C99F1F
:104DC000700DD89F700D112477FD3AC075956795C9
:104DD00075956795260F371F30932205209321057F
:104DE0000E94DE25982F80919B029817E1F0909306
:104DF0009B0210929C02DF91CF911F910895109217
:104E00002205109221051092200510921F05109284
:104E10001E0510921D0510921C0510921B05DF91B6
:104E2000CF911F91089580919C02883CC0F78F5FBD
:104E300080939C02F4CF1092200510921F058ACF18
:104E40006D5F7F4FC3CFEE27FF27EC1BFD0BA6CF77
:104E50008BE195E00895843068F0E82FF0E0EE0FE4
:104E6000FF1FEB5DFA4F0190F081E02DED58FF4FF1
:104E7000CF010895E82FF0E0EB58FA4FE481F0E01D
:104E8000EE0FFF1FED5DFA4F0190F081E02DED5820
:104E9000FF4FCF0108958091990290919A02803A34
:104EA000910594F48091990290919A028C38910521
:104EB0004CF48091990290919A028837910534F4CC
:104EC00081E0089583E0089584E0089582E00895E4
:104ED000089580919C02883C11F080E008958091B3
:104EE0009B02089580917505E82FF0E0EE0FFF1FFB
:104EF000ED5DFA4F8081918187349105B4F0809106
:104F00007605E82FF0E0EE0FFF1FED5DFA4F808190
:104F10009181873491053CF4808191818A5B9F4F18
:104F2000FCF083E0089582E00895808191818A5B9E
:104F30009F4FC4F480917605E82FF0E0EE0FFF1F3D
:104F4000ED5DFA4F80819181873491053CF4808139
:104F500091818A5B9F4FE4F087E0089588E008958F
:104F600084E0089580917605E82FF0E0EE0FFF1FB2
:104F7000ED5DFA4F80819181873491055CF48081E9
:104F800091818A5B9F4F14F080E0089585E0089539
:104F900086E0089581E00895CF93DF93682F809194
:104FA0007605A82FB0E0AA0FBB1FFD01ED5DFA4FFB
:104FB0002081318180919D05482F50E04217530791
:104FC00024F48091C00582FD75C062FD61C0FD01C1
:104FD000ED5DFA4F80819181CC27DD27C41BD50B75
:104FE0008C179D0724F48091C00583FD61C063FD8B
:104FF00040C080917505A82FB0E0AA0FBB1FFD012E
:10500000ED5DFA4F808191814817590724F4809112
:10501000C00580FD51C060FD1EC0FD01ED5DFA4F71
:10502000808191818C179D0724F48091C00581FDBA
:1050300045C061FF0CC0AD5DBA4F2D913C91809190
:105040009E05C81BD109C217D3070CF46D7E862FAD
:10505000DF91CF910895FD01ED5DFA4F20813181FF
:1050600080919E05481B510924173507B4F66E7EC2
:10507000D4CFAD5DBA4F2D913C9180919E05FE013C
:10508000E81BF109E217F3070CF0B3CF677DB1CF4E
:10509000FD01ED5DFA4F2081318180919E05FA017D
:1050A000E81BF1092E173F070CF091CF6B7D8FCFD6
:1050B00068629FCF64628BCF6161AFCF6261862FE0
:1050C000DF91CF91089580917505A82FB0E0AA0FC8
:1050D000BB1FFD01ED5DFA4F808191818D5E9F4F79
:1050E00014F010928601AD5DBA4F8D919C918A5B50
:1050F0009F4F44F480918601882321F481E08093BE
:105100008601089580E00895E82FF0E0EE0FFF1F7C
:10511000EB59FD4F60817181882777FD8095982F2D
:1051200023EC30E040E050E00E94AC4108956091F3
:10513000650270916602882777FD8095982F23EC91
:1051400030E040E050E00E94AC416093590570931C
:105150005A0580935B0590935C056091670270919E
:105160006802882777FD8095982F0E94AC41609354
:105170005D0570935E0580935F05909360050895CB
:105180008091BA049091BB042091B2023091B30295
:10519000820F931F67E070E00E94EB4170934E0511
:1051A00060934D058091A9049091AA04820F931FEA
:1051B00067E070E00E94EB417093660560936505BF
:1051C00080919A0490919B0490936205809361056D
:1051D00080918D0490918E042091AC023091AD02AB
:1051E000820F931F9093AD028093AC028091BC0418
:1051F0009091BD042091B4023091B502820F931FAB
:1052000067E070E00E94EB417093500560934F059A
:105210008091AB049091AC04820F931F67E070E023
:105220000E94EB41709368056093670580919C0430
:1052300090919D04909364058093630580918F0401
:10524000909190042091AE023091AF02820F931F93
:105250009093AF028093AE028091B0029091B10220
:1052600001969093B1028093B002209197043091FF
:1052700098048091B6029091B702820F931F909389
:1052800054058093530510921601EAE7F0E08081FF
:10529000886C808308952F923F924F925F926F9215
:1052A0007F928F929F92AF92BF92CF92DF92EF92B6
:1052B000FF920F931F93DF93CF93CDB7DEB728975D
:1052C0000FB6F894DEBF0FBECDBF80918C0288234D
:1052D00079F420919104309192048091C601482F75
:1052E00050E088279927841B950B28173907DCF590
:1052F0008091B103877F8093B1038091B203877F50
:105300008093B2031092C6031092C5031092C80393
:105310001092C7031092D4031092D3031092D603B5
:105320001092D5031092AB021092AA021092A90219
:105330001092A80228960FB6F894DEBF0FBECDBF1C
:10534000CF91DF911F910F91FF90EF90DF90CF9061
:10535000BF90AF909F908F907F906F905F904F9095
:105360003F902F9008958091910490919204481756
:1053700059070CF4BDCF8091B10388608093B103CD
:10538000209189058091880290918902805C9F4FCD
:105390008138910508F09CC031E0809180029091A5
:1053A00081028134910540F48091820290918302C0
:1053B0008134910508F48FC026958091B203877FD0
:1053C0008093B203822F90E0A0E0B0E089839A83BB
:1053D000AB83BC8348EE642E43E0742E812C912C69
:1053E000681A790A8A0A9B0A35EC432E33E0532E59
:1053F000A9E5B5E0BE83AD8328EA222E22E0322E55
:1054000018861F82EF81F885EE0FFF1FEB59FD4FC5
:1054100060817181882777FD8095982F23EC30E09B
:1054200040E050E00E94AC417B018C0129E830E073
:1054300040E050E00E942042F20131832083AD81A0
:10544000BE81AD90BD90CD90DC90C801B70129819F
:105450003A814B815C810E94AC417B018C01C4018B
:10546000B301A60195010E94AC41E60EF71E081F8C
:10547000191FC801B70128EE33E040E050E00E9458
:105480002042C901DA01ED81FE8181939193A193BC
:10549000B193FE83ED838A199B09D1012D913C9133
:1054A000280F391FF101219331931F01D2011F965B
:1054B0009C938E931E97EF81F8853196F887EF8342
:1054C00082E090E0480E591E329709F09BCF32CF10
:1054D000269530E062CF332309F46FCF8091B20379
:1054E00088608093B2036ECF9F92AF92BF92CF92AB
:1054F000DF92EF92FF920F931F93CF93DF938091F0
:105500008D0190918E01019790938E0180938D0172
:10551000892B09F056C080E091E090938E01809332
:105520008D019090A4058091A505A82EBB24CC24C4
:10553000DD24CA18DB0868EAE62E62E0F62EC2EB2C
:10554000D2E007ED13E0F70120813181B901660F48
:10555000771F660F771F660F771F621B730B8827F5
:1055600077FD8095982F60587F4F8F4F9F4F20E099
:1055700031E040E050E00E942042DA01C901692D8B
:1055800070E00E94EB419B0188819981860F971FF3
:10559000998388838C159D0504F5D982C882C6013C
:1055A000F80131832083958B848BF701119211923E
:1055B0007F0122960E5F1F4FFCEAEF16F2E0FF0616
:1055C00011F6DF91CF911F910F91FF90EF90DF9037
:1055D000CF90BF90AF909F900895A816B90604F79A
:1055E000B982A882C501DCCFAF92BF92CF92DF9281
:1055F000EF92FF920F931F93CF93DF938091A702B7
:10560000882321F08091910280FF68C16091590543
:1056100070915A0580915B0590915C0520E032E025
:1056200040E050E00E942042E90137FD92C16091C4
:105630005D0570915E0580915F059091600520E0A9
:1056400032E040E050E00E942042690137FD7CC119
:10565000CC16DD060CF410C1809187019091880171
:1056600097FD11C1845E9D4F7C010027F7FC0095DA
:10567000102F6091550570915605809157059091B6
:10568000580521E53BEF4FEF5FEF0E942042E20E0D
:10569000F31E041F151FC801B70128E631E040E0E2
:1056A00050E00E942042645B7040809153059091CD
:1056B000540597FDF0C0813891050CF0F3C0EB0163
:1056C000CC0FDD1FCC0FDD1FCC0FDD1F80918B01B8
:1056D00090918C01892BA9F489E1C816D1048CF42E
:1056E00080914B0590914C05860F971F90934C0528
:1056F00080934B058091A5029091A602892B09F019
:10570000FDC0B60175956795759567957595679513
:105710006F5F7F4FCE010E94EB419B01442737FD15
:105720004095542F8091550590915605A0915705AD
:10573000B0915805280F391F4A1F5B1F209355054C
:105740003093560540935705509358058091B90101
:10575000C82FD0E0CC9EC001CD9E900DDC9E900D58
:10576000112497FDEFC0959587959595879595950B
:10577000879595958795959587955E01A81AB90A9D
:10578000B7FCA5C080918B0190918C01009709F026
:105790008EC0C0908202D09083028091800290914E
:1057A0008102C80ED91ED694C794D694C794D694B5
:1057B000C79480E490E0C80ED91E80918901909131
:1057C0008A01AA2797FDA095BA2FECE1EE2EE2E020
:1057D000FE2E012D112DE81AF90A0A0B1B0BCA0126
:1057E000B9012FEA34E040E050E00E942042E20E8E
:1057F000F31E041F151FC801B70128E631E040E081
:1058000050E00E942042645B70406A9DC0016B9D25
:10581000900D7A9D900D1124B6010E94EB419B01E1
:10582000CE01880F991F8C0F9D1F821793070CF4D0
:1058300063C044275527481B590BB9012417350766
:105840000CF4BA019B01442737FD4095542F8091F9
:105850006D0590916E05A0916F05B0917005820F56
:10586000931FA41FB51F80936D0590936E05A093A1
:105870006F05B093700520C06E01809187019091F3
:10588000880197FFEFCE60E070E080915305909122
:10589000540597FF10CF909581959F4F81389105C2
:1058A0000CF40DCF60E070E0C0E0D0E00FCF0197C6
:1058B00090938C0180938B01DF91CF911F910F9179
:1058C000FF90EF90DF90CF90BF90AF90089584EF5E
:1058D00091E090938C0180938B01EECF0E949D1FED
:1058E000882351F38091A7028F5F8093A7028530B0
:1058F000A0F50E94823DE0CFBC01A4CF88EC90E0EF
:105900000E94293D0091870110918801B8018827E4
:1059100077FD8095982F2FEA34E040E050E00E9418
:10592000AC4160935505709356058093570590934D
:10593000580510938A01009389011092A6021092D3
:10594000A502DFCE4F960FCFD094C194D108D39447
:105950007FCED095C195DF4F6ACE88EE93E00E944E
:10596000293DAACF2F923F924F925F926F927F92E2
:105970008F929F92AF92BF92CF92DF92EF92FF925F
:105980000F931F93DF93CF93CDB7DEB72C970FB64E
:10599000F894DEBF0FBECDBF6091590570915A05D6
:1059A00080915B0590915C050E94DB219A8389833D
:1059B00060915D0570915E0580915F059091600535
:1059C0000E94DB216C0160915D0570915E05809104
:1059D0005F05909160050E9494218C0160915905AA
:1059E00070915A0580915B0590915C050E94F121B0
:1059F0001C016090650570906605882477FC809492
:105A0000982CC601AA2797FDA095BA2F8F83988757
:105A1000A987BA87A0905305B0905405CC24B7FC51
:105A2000C094DC2CC801AA2797FDA095BA2F8B83C0
:105A30009C83AD83BE836F81788589859A85A40117
:105A400093010E94AC417B018C016B817C818D8133
:105A50009E81A60195010E94AC41E61AF70A080B47
:105A6000190BC801B70120E030E140E050E00E948E
:105A7000204230936A0520936905A0916705B09193
:105A80006805BC87AB8760915D0570915E0580916C
:105A90005F05909160050E94DB21AA2797FDA095E4
:105AA000BA2FBC01CD01A60195010E94AC4120E0B6
:105AB00032E040E050E00E94204279018A016B818F
:105AC0007C818D819E81A40193010E94AC4120E0E4
:105AD00032E040E050E00E942042E20EF31E041F3C
:105AE000151F442437FC4094542CC801B701A2016F
:105AF00091010E94AC4120E030E840E050E00E947B
:105B00002042EB85FC85E20FF31FF0936C05E093D8
:105B10006B0589819A815C01CC24B7FCC094DC2C94
:105B20002091530530915405442737FD4095542F5B
:105B30006F81788589859A850E94AC41A60195017F
:105B40000E94204279018A01209165053091660505
:105B5000442737FD4095542F6B817C818D819E8138
:105B60000E94AC41A60195010E942042E20EF31E64
:105B7000F0925205E09251052C960FB6F894DEBFD4
:105B80000FBECDBFCF91DF911F910F91FF90EF908E
:105B9000DF90CF90BF90AF909F908F907F906F904D
:105BA0005F904F903F902F900895EF92FF920F9348
:105BB0001F9380918C02882321F480917D0586FDBE
:105BC00013C1809165059091660590936A05809355
:105BD0006905809167059091680590936C058093A5
:105BE0006B05609153057091540570935205609355
:105BF000510580915105909152057C010027F7FCD9
:105C00000095102F8091550590915605A09157054C
:105C1000B0915805E80EF91E0A1F1B1FE0925505AA
:105C2000F092560500935705109358059B014427A1
:105C300037FD4095542F80916D0590916E05A09190
:105C40006F05B0917005820F931FA41FB51F80933D
:105C50006D0590936E05A0936F05B093700588E174
:105C6000E81686E9F80686E0080780E018070CF4D5
:105C700082C088EE99E6A9EFBFEFE80EF91E0A1F71
:105C80001B1FE0925505F09256050093570510939F
:105C900058058091690590916A059C01442737FD5C
:105CA0004095542F8091590590915A05A0915B051C
:105CB000B0915C05280F391F4A1F5B1F20935905BF
:105CC00030935A0540935B0550935C05293493EC5F
:105CD000390793E0490790E059070CF03FC0293B92
:105CE000ACE33A07ACEF4A07AFEF5A070CF46FC0CA
:105CF00080916B0590916C059C01442737FD409580
:105D0000542F80915D0590915E05A0915F05B09143
:105D10006005280F391F4A1F5B1F20935D053093D4
:105D20005E0540935F05509360052934B3EC3B0753
:105D3000B3E04B07B0E05B078CF120593648474091
:105D4000504020935D0530935E0540935F0550936E
:105D500060051F910F91FF90EF90089520593648EC
:105D6000474050402093590530935A0540935B05B6
:105D700050935C05BDCF17FF8CCF88E196E9A6E074
:105D8000B0E0E80EF91E0A1F1B1FE0925505F092C5
:105D9000560500935705109358057BCF293B8CE39C
:105DA00038078CEF48078FEF58079CF62057394784
:105DB000484F5F4F20935D0530935E0540935F052C
:105DC000509360051F910F91FF90EF900895205719
:105DD0003947484F5F4F2093590530935A054093F8
:105DE0005B0550935C0584CF0E94B22C60915305F3
:105DF00070915405FECE0E94C0280E94D52D80913E
:105E0000690590916A059093C0038093BF038091C8
:105E10006B0590916C059093C2038093C1038091B0
:105E20005105909152059093C4038093C3038091D0
:105E30004D0590914E059093BA038093B9038091DC
:105E40004F05909150059093BC038093BB038091C4
:105E50005305909154059093BE038093BD030E9417
:105E60004B290E94742A08951092CA011092C90108
:105E70001092B7021092B60210924C0510924B0588
:105E80001092B5021092B4021092B3021092B202B4
:105E90001092AB021092AA021092A9021092A802CC
:105EA0000E9436186091650270916602882777FD1E
:105EB0008095982F23EC30E040E050E00E94AC4108
:105EC0006093590570935A0580935B0590935C0528
:105ED0006091670270916802882777FD8095982FFE
:105EE0000E94AC4160935D0570935E0580935F05F1
:105EF0009093600510926D0510926E0510926F05DB
:105F000010927005609187017091880170938A01E9
:105F100060938901882777FD8095982F2FEA34E0D8
:105F200040E050E00E94AC416093550570935605E7
:105F3000809357059093580508959C018091C40162
:105F4000823031F0833081F0813029F0C901089529
:105F50006217730764F4620F731F77FD0EC09B0115
:105F600035952795C901089526173707A4F3220F01
:105F7000331F261B370BC90108956F5F7F4FEFCF8B
:105F80000F93382FE62F8CE398E2632F70E00E9486
:105F9000EB417093900160938F01E0937305409300
:105FA000720520937105009374050F9108950F9366
:105FB0009091BE0180917D0582FD0EC04091BC0193
:105FC0002091BB01265F892F8F5F622F0091C50151
:105FD0000E94C02F0F91089540E0F2CF0F9381E20D
:105FE0006AE548E72AE508E70E94C02F0F91089567
:105FF0002F923F924F925F926F927F928F929F92D9
:10600000AF92BF92CF92DF92EF92FF920F931F93C6
:10601000DF93CF93CDB7DEB7E4970FB6F894DEBF2A
:106020000FBECDBF0E94DC1F0E94FB2E20918A0272
:1060300030918B02388F2F8B0E94A01F833008F085
:106040006FC48091DC018A3009F450C3843109F4B3
:106050004DC328980E942E3D8091D1029091D2028A
:10606000009709F44DC301979093D2028093D10217
:1060700080918F02909190028150914008F0C0C4AD
:10608000809191028E7F80939102E0918C02EE23A9
:1060900051F080919C0590E02F89388D82179307ED
:1060A00014F4988F8F8B2091880230918902A90176
:1060B00037FD99C48091860590E0880F991F880F5D
:1060C000991F841795070CF415C480917D05682FDE
:1060D00070E0C901AA2797FDA095BA2F20916D0500
:1060E00030916E0540916F0550917005281B390B5A
:1060F0004A0B5B0B20936D0530936E0540936F0543
:1061000050937005203B8CE338078FEF48078FEFE3
:1061100058070CF0D3C380EB9CE3AFEFBFEF809345
:106120006D0590936E05A0936F05B093700568722E
:106130007070672B09F0D9C38091BA01A82FB0E025
:10614000BE8BAD8B2E2F30E03CA32BA3309172057C
:106150003AA3432F50E060E070E04E8F5F8F68A35A
:1061600079A380917305282E332444245524BE013D
:106170006B5F7F4F7C8B6B8BCE0109969A8B898BE3
:106180004DE4642E45E0742E31E6832E35E0932EE7
:1061900029E5E22E25E0F22E5B016C0100E010E023
:1061A00080E190E0002E02C0880F991F0A94E2F768
:1061B000ABA1BCA18A239B23892B09F4BEC2F601A3
:1061C00011821082D3012D913C91442737FD4095D7
:1061D000542FC201B1010E94AC4120E430E040E004
:1061E00050E00E942042F40180819181AD89BE89F6
:1061F000A89FB001A99F700DB89F700D112477FD65
:106200008CC3759567957595679575956795759523
:106210006795620F731FF60180819181680F791F66
:10622000D5016D937C93B0EC60307B070CF0B6C267
:1062300020E030ECF501318320830F5F1F4F22E017
:1062400030E0A20EB31EC20ED31E620E731E820E6B
:10625000931E44E050E0E40EF51E0230110509F0F3
:106260009FCFE0915305F0915405209171059090D6
:106270007405A0906D05B0906E05C0906F05D0902C
:106280007005809196028823C1F080918F029091D1
:1062900090020297C09758F46F89788D16161706EA
:1062A00034F481E090E09093900280938F0280918B
:1062B0008705A82FB0E0B88FAF8B2F88388C220CC1
:1062C000331C220C331CEE0FFF1FBF01882777FD04
:1062D0008095982F30E040E050E00E94AC4120E4EF
:1062E00030E040E050E00E94204279018A01692DAF
:1062F00070E080E090E0A60195010E94AC4120EFA3
:1063000035E540E050E00E942042C701820F931F14
:10631000B0E481309B0714F080E090E49C01E0EC55
:1063200080309E0714F420E030EC80918802909138
:106330008902880F991F880F991FA901481B590BC3
:10634000F1EA2F1631040CF4AAC2C10137FC66C36E
:106350009595879522273327281B390B421753071A
:106360003CF0910135952795421753070CF440C333
:1063700080918805682F70E0788B6F87CB01880F3C
:10638000991F880F991F7101E81AF90A2E153F0508
:106390003CF0821993097901821793070CF47C0170
:1063A0009701F7FC1BC335952795220D331DB901C5
:1063B000882777FD8095982F2091CC0130E040E030
:1063C00050E00E94AC4120E430E040E050E00E9408
:1063D0002042390144245524421A530A80918F01E6
:1063E000909190019C0140E050E02A8F3B8F4C8FB0
:1063F0005D8F03EDA02E02E0B02E14E8812E12E096
:10640000912E00E010E03AA1332309F4ABC1D4018E
:106410006D917C91E989FA8920813181261B370BA6
:10642000442737FD4095542FF50180819181A28149
:10643000B381820F931FA41FB51F80839183A28312
:10644000B383AB89BC89CD90DC90C61AD70AF8011A
:10645000EE0FFF1FEE0FFF1FED52FD4F60817181A8
:1064600082819381603026E072072FEF82072FEF41
:1064700092070CF0A4C140E056E06FEF7FEF40833D
:1064800051836283738360E076E08FEF9FEF2A8D04
:106490003B8D4C8D5D8D0E9420422C0D3D1DF801E1
:1064A000EE0FFF1F81E090E08C0F9D1FE80FF91F9A
:1064B00031832083241535050CF07AC15182408246
:1064C0000F5F1F4FA4E0B0E0AA0EBB1EE989FA8956
:1064D0003296FA8BE98B22E030E0820E931E4B89D4
:1064E0005C894E5F5F4F5C8B4B8B0230110509F06E
:1064F0008ACF49815A815093CC034093CB032B819F
:106500003C813093CE032093CD03F092D003E092F0
:10651000CF033092D2032092D10380918705682F58
:1065200070E07E876D8770913F02798FFFED4F2E6F
:10653000F4E05F2EEFED8E2EE3E09E2E7FEDA72E92
:1065400075E0B72E69EB662E62E0762ECC24DD2452
:10655000C901AA2797FDA095BA2F8DA39EA3AFA32B
:10656000B8A7BA01882777FD8095982F69A77AA7E1
:106570008BA79CA7C101AA2797FDA095BA2F8DA72D
:106580009EA7AFA7B8AB9701442737FD4095542F7E
:1065900029AB3AAB4BAB5CAB93C0D5013C90131429
:1065A0000CF092C012966C91772767FD7095872F3B
:1065B000972F2DA13EA14FA158A50E94AC4120E4E8
:1065C00030E040E050E00E94204279018A01F5016C
:1065D0006181772767FD7095872F972F29A53AA5A9
:1065E0004BA55CA50E94AC4120E430E040E050E0C7
:1065F0000E942042E20EF31E232D332727FD309503
:10660000432F532F6DA57EA58FA598A90E94AC415D
:1066100020E430E040E050E00E942042E20EF31E11
:10662000D50113962C91332727FD3095432F532FF7
:1066300069A97AA98BA99CA90E94AC4120E430E009
:1066400040E050E00E942042E20EF31EF301608120
:106650007181C7010E949D2FD3018C9311969C9349
:1066600097FD1BC19595879595958795ED85FE8539
:106670008E179F070CF055C0CF01009709F45BC03F
:10668000D2018C93E3E0EC1528F0D2018C91F40157
:10669000808311820894C11CD11C25E030E0420E99
:1066A000531E42E050E0840E951E64E070E0A60E9A
:1066B000B71E640E751E7CE0C716D10409F491C0A4
:1066C0008091910280FD69CFB98DBB23F9F0F6016D
:1066D000EE0FFF1FEE0FFF1FEC0DFD1DE152FB4FF4
:1066E000D601A05CBD4F8C918083CCCF289A0E94AC
:1066F0002E3D8091D1029091D202009709F0B3CC47
:10670000809191028E7E80939102BFCCF601EE0FB4
:10671000FF1FEE0FFF1FEC0DFD1DE152FB4F10821E
:10672000B1CF2F853889281739070CF0A6CFC901BA
:10673000009709F0A5CF81E0A3CFD7012D913D911E
:106740004D915C916E8D7F8D88A199A10E94AC4185
:1067500028EF3AE240E050E00E942042F601318307
:10676000208330CDEB89FC89C080D180D4018D910C
:106770009C91C81AD90A9601442737FD4095542F99
:10678000F50180819181A281B381820F931FA41FA3
:10679000B51F80839183A283B38359CE6150704427
:1067A0000CF44BCDE0E0F0E4D501ED93FC9345CD46
:1067B000621673060CF084CE7182608281CE6130E5
:1067C0005AEF750750E0850750E095070CF45FCE4F
:1067D00060E07AEF80E090E060837183828393834E
:1067E00056CE80E00E945822809191018150809382
:1067F00091018823C9F588E1809391016091590541
:1068000070915A0580915B0590915C0529E830E014
:1068100040E050E00E9420423093B4032093B30341
:1068200060915D0570915E0580915F0590916005B6
:1068300029E830E040E050E00E9420423093B60367
:106840002093B503609155057091560580915705C9
:10685000909158052FEA34E040E050E00E94204239
:106860003093B8032093B703E4960FB6F894DEBFD5
:106870000FBECDBFCF91DF911F910F91FF90EF9091
:10688000DF90CF90BF90AF909F908F907F906F9050
:106890005F904F903F902F9008950396E3CECA01EA
:1068A0004135510514F080E590E09C014FEF803BAD
:1068B00094070CF05DCD20EB3FEF5ACD2155334CC2
:1068C000404050400CF433CC80E593ECA0E0B0E0C5
:1068D00080936D0590936E05A0936F05B09370053E
:1068E00068727070672B09F427CC0E94F42AE0913B
:1068F0008C0222CC88EE93E090938C0180938B01E4
:1069000080917D05682F70E084FDE3CB81E090E00D
:106910009093A6028093A502DCCB615F7F4F71CC80
:106920000E94A01F8330B0F0809191028F7E8093EF
:1069300091028091900590E028EE31E0BC01629FC9
:10694000C001639F900D729F900D11249093D2020D
:106950008093D1028F89988D8997B4F080919102AC
:1069600080FF12C080918F0290919002AFEF8F3F15
:106970009A0729F001969093900280938F020E94CB
:10698000183E0E94D72F81CB80918F029091900268
:106990008F3F910509F070F51092D7021092D8023E
:1069A0001092D9021092DA021092D3021092D402FD
:1069B0001092D5021092D6028A3F910501F781E02C
:1069C00090E09093A6028093A50210926D0510921C
:1069D0006E0510926F0510927005D1CF22273327D4
:1069E0002E193F09E0CC44275527421B530B62CB9D
:1069F0009A01BECC80919102826080939102BFCFB8
:106A000080918F05482F50E0588F4F8B80919102D5
:106A10008061809391020E94EE2F37CB019698CC33
:106A2000809191028460809391028FEF8093D901CD
:106A30001092DA0180E28093DB010E94F320089536
:106A400010929305109294051092950588E080931A
:106A5000960585ED8093A70582E08093A80588E7D9
:106A60008093A9058AE08093AA050895E5E7F5E0FB
:106A700082E08093750581E08093760583E08093C2
:106A8000770574E07093780525E020937905A6E0FA
:106A9000A0937A0587E080937B0558E050937C05AE
:106AA00084E480937D054EE140937E058BEF8093D7
:106AB00080058AE08093810540937F05409383059C
:106AC00070938205509384058CE0809385058093B4
:106AD00086055093870586EE8093880580E880932D
:106AE0008A0580E580938B0534E630938C056FE54D
:106AF00060938E0583E280938F05409390051092FA
:106B0000910580E2809392053093970588E2809307
:106B100098051092C10592E39093990586E98093B8
:106B20009A0520939B0590939C052AE520939D054B
:106B300090939E051092C00520939F0583E4809357
:106B4000A0051092A1059093A6056093AB0583EF75
:106B50008093AD058FE08093AC058093AE058DEFFB
:106B60008093AF053093B0052093B10525AF26AFD4
:106B70008BE487AF8093B5058093B6051092B70577
:106B8000A093B8055093B9052093BA054093BB056F
:106B90003093BC053093BD057093BE0508958050B9
:106BA00090400E9461420895682F863030F065E081
:106BB00082E090E00E94794208958823C9F761E05D
:106BC00082E090E00E947942089582E090E00E9485
:106BD0006142863008F4089582E090E063E00E940C
:106BE000794283E00895805090400E947942089550
:106BF00081E08093D205EFEDF5E080E009C090E000
:106C000090831182128213828F5F3496803159F003
:106C10008430A8F790E490831182128213828F5FF0
:106C200034968031A9F790E49093E0059093E205C3
:106C300080EC8093E4059093E6058093E9058093CA
:106C4000EA059093ED058093EE05A3EDB5E0E2E94A
:106C5000F1E087E001900D928150E1F70895809175
:106C6000D205813011F080E0089582ED95E068EE64
:106C700073E04DE450E00E946F4281E0089588EE99
:106C800093E00E946142813011F080E0089582ED2E
:106C900095E068EE73E04DE450E00E94514281E0DF
:106CA0000895805090400E94874208951F93182FA6
:106CB000863000F115E068ED71E06050704085E7C6
:106CC00095E04DE550E00E946F4282E690E06DE570
:106CD00070E00E94874285E795E060E570E048E05B
:106CE00050E00E946F42812F0E94D4350E94111FF4
:106CF0001F9108958823E1F390E001972DE530E09E
:106D0000829FB001839F700D929F700D11246C596A
:106D10007F4FD3CF982F8150853068F06EE171E0BE
:106D20006050704085E795E04DE550E00E9451428B
:106D30000E94111F0895892F90E001972DE530E002
:106D4000829FB001839F700D929F700D11246C592A
:106D50007F4FE6CF805090400E94694208950E9484
:106D600036350E948E3E0E94203580EC80937D0552
:106D700083E08093820584E18093900586E480938C
:106D8000A1058EE18093AC058093AE05A6ECB5E03D
:106D9000EAE9F1E089E001900D928150E1F7089570
:106DA0000E9436350E948E3E0E94203580EC8093F2
:106DB0007D0583E08093820584E18093AC05809318
:106DC000AE05A6ECB5E0E4EAF1E087E001900D92B3
:106DD0008150E1F708950E9436350E948E3E0E9450
:106DE000203580EC80937D05A6ECB5E0ECEAF1E07F
:106DF00086E001900D928150E1F708950F931F9363
:106E0000CF93DF9381E090E00E9461428B3409F4DC
:106E10004FC000D00F92ADB7BEB711961C9211971C
:106E20008BE598E013969C938E9312970E94B70E71
:106E30000F900F900F9088EE93E06FEF0E947942D1
:106E400080E590E00E94614200E08C3008F494C03C
:106E500080E08F5F843011F00023D9F711E0123009
:106E600031F0133009F485C0113009F47FC00E945D
:106E7000D036002379F0C0E0D0E0CE01805B9F4F98
:106E80000E946142FE01EB58FA4F80832196C83080
:106E9000D10599F7812F0E9456361F5F1630F9F6FB
:106EA00081E00E94D43581E090E06BE40E94794259
:106EB0000E94E5350E948A360E94E53500D000D058
:106EC0000F92EDB7FEB73196ADB7BEB711961C92D3
:106ED00022E438E032832183838314820E94B70E38
:106EE0000F900F900F900F900F900E943F368823C5
:106EF00009F444C0EFEDF5E020E0808118160CF4B1
:106F00002F5F349686E0EF31F807B9F72093B80287
:106F1000ADB7BEB717970FB6F894BEBF0FBEADBFE3
:106F2000EDB7FEB7319611961C9280E098E09283FF
:106F3000818383ED95E094838383258316820E9469
:106F4000B70E0F900F900F900F90EDB7FEB7118214
:106F50008FED97E0938382830E94B70E0F900F907E
:106F60000F90DF91CF911F910F9108950E94EB3602
:106F700080CF0E94AF367DCF01E06ACF00D00F9264
:106F8000EDB7FEB7118281E298E0938382830E947D
:106F9000B70E0F900F900F900E94F8350E942F3679
:106FA000A9CF9FB7F8948091C9008F778093C900CB
:106FB0008091C9008F7B8093C9008091C9008F7D2B
:106FC0008093C9005A9A52985B9A539A1092CD00B6
:106FD0008AE28093CC008091C80082608093C800D0
:106FE00088E18093C9008091CA008F778093CA009E
:106FF0008091CA008F7B8093CA008091CA008F7DE8
:107000008093CA008091CA008F7E8093CA008091CD
:10701000CA00877F8093CA008091C9008B7F8093CC
:10702000C9008091CA0084608093CA008091CA0020
:1070300082608093CA008091C80087FF06C080915B
:10704000CE008091C80087FDFACF8091C90080688A
:107050008093C9009FBF08951F920F920FB60F92A1
:1070600011248F938091CE008F910F900FBE0F90BF
:107070001F9018958091B5049091B604A091B70423
:10708000B091B80420912F0630913006409131061E
:1070900050913206281B390B4A0B5B0BB901CA0110
:1070A00008958091B5049091B604A091B704B09171
:1070B000B80480932F0690933006A0933106B093C6
:1070C00032062091B5043091B6044091B704509136
:1070D000B804821B930BA40BB50B809323069093EB
:1070E0002406A0932506B093260610921F06109240
:1070F0002006109221061092220610922706109266
:1071000028061092290610922A0608958F929F92BF
:10711000AF92BF92CF92DF92EF92FF920F931F93A5
:107120008091B5049091B604A091B704B091B804D1
:1071300040912F06509130066091310670913206D1
:10714000481B590B6A0B7B0B80911F069091200600
:10715000A0912106B091220684179507A607B707CC
:1071600044F440931F0650932006609321067093C9
:10717000220680917D0581FF55C08091B103816019
:107180008093B1038091B6018852803B08F47EC0A1
:107190009091E602993208F05AC0983209F47EC004
:1071A0009F5F9093E6028091E1028F5F8093E102FE
:1071B000803309F054C01092E10280918205882E3C
:1071C0009924AA24BB24C0902306D0902406E090E2
:1071D0002506F0902606950184010C0D1D1D2E1D1F
:1071E0003F1D80912B0690912C06A0912D06B09109
:1071F0002E0680179107A207B3075CF4970186015A
:10720000081919092A093B09081719072A073B0712
:1072100034F100932306109324062093250630931F
:1072200026061DC08091B1038E7F8093B1038091AB
:10723000B60124E6829FC0011124A0E0B0E0809353
:107240002B0690932C06A0932D06B0932E068091CA
:10725000E1028F5F8093E102803309F4ACCFCB0170
:10726000BA0124E630E040E050E00E942042309332
:10727000F0032093EF031F910F91FF90EF90DF90A9
:10728000CF90BF90AF909F908F9008951092E6029C
:107290008091B2038E7F8093B203D9CF40932B06A7
:1072A00050932C0660932D0670932E068091B203A6
:1072B00081608093B20374CFCF92DF92EF92FF92FE
:1072C0000F931F93CF93DF936C018091B50490913E
:1072D000B604A091B704B091B80420912F06309164
:1072E00030064091310650913206281B390B4A0B6B
:1072F0005B0BE0902306F090240600912506109188
:1073000026068091E2029091E302E901C81BD90BA5
:107310002093E2023093E3024093E4025093E502AB
:107320001C161D060CF0BEC08091B10382608093D4
:10733000B1038091B2038D7F8093B203E21AF30A06
:10734000040B150B2091810530E040E050E0C801AE
:10735000B7010E94AC4128EE33E040E050E00E94CB
:10736000204280917F0590E0BC01C69FC001C79F6D
:10737000900DD69F900D1124281B390B80917E050E
:10738000482F50E0421753074CF088279927841B59
:10739000950BA901281739070CF466C080917D056B
:1073A00080FF04C081FD75C0C40ED51E7E0100277C
:1073B000F7FC0095102F6091DB027091DC02809148
:1073C000DD029091DE0228E130E040E050E00E94D2
:1073D000AC41E60EF71E081F191FC801B70129E1CD
:1073E00030E040E050E00E94204279018A01E092C2
:1073F000DB02F092DC020093DD021093DE022091AA
:10740000B3013091B401C901880F991F820F931FF6
:10741000880F991F880F991F880F991F8C0D9D1D2C
:1074200069E170E00E94D7416093B3017093B401A9
:1074300080918F0290919002885E934030F083E0BB
:10744000E816F104010511058CF08091B1038B7FE2
:107450008093B103C601DF91CF911F910F91FF90EF
:10746000EF90DF90CF900895AC0198CF2EEFE21609
:107470002FEFF2062FEF02072FEF120734F360937E
:10748000DF027093E0028091B10384608093B103C6
:10749000E1CF8091B6018852803B08F487CFC40EBB
:1074A000D51E84CF209709F449CF8091B203826022
:1074B0008093B2038091B1038D7F8093B1033ECF5F
:1074C000CF93DF93E0918005EF3F59F0EB3F08F455
:1074D000ACC1F0E0EE0FFF1FEF50FF4F80818093B3
:1074E000B601E0917F05EF3F59F0EB3F08F49AC1F8
:1074F000F0E0EE0FFF1FEF50FF4F80818093B5014A
:107500008091B501882309F04AC11092B501E0913C
:107510008105EF3F59F0EB3F08F481C1F0E0EE0F39
:10752000FF1FEF50FF4F80818093B7018091B7011B
:10753000882309F02DC11092B701E0918305EF3F38
:1075400059F0EB3F08F468C1F0E0EE0FFF1FEF5079
:10755000FF4F80818093B801E0918A05EF3F59F099
:10756000EB3F08F456C1F0E0EE0FFF1FEF50FF4F66
:1075700080818093B901E0918B05EF3F59F0EB3F9B
:1075800008F444C1F0E0EE0FFF1FEF50FF4F808181
:107590008093BB018091BB018B3008F0F3C08AE07F
:1075A0008093BB01E0918C05EF3F59F0EB3F08F46D
:1075B0002AC1F0E0EE0FFF1FEF50FF4F8081809354
:1075C000BC01E0918D05EF3F59F0EB3F08F418C185
:1075D000F0E0EE0FFF1FEF50FF4F80818093BA0164
:1075E000E0919205EF3F59F0EB3F08F406C1F0E05F
:1075F000EE0FFF1FEF50FF4F80818093BE01A3E984
:10760000B5E0CFEBD1E0EC91EF3F51F0EB3F08F468
:10761000B7C0F0E0EE0FFF1FEF50FF4F808188836F
:107620001196219685E0A739B80769F75096C3EC03
:10763000D1E0EC91EF3F51F0EB3F08F49FC0F0E058
:10764000EE0FFF1FEF50FF4F808188831196219628
:1076500085E0AB3AB80769F7E0919705EF3F59F03D
:10766000EB3F08F4C7C0F0E0EE0FFF1FEF50FF4FF5
:1076700080818093C701E0919C05EF3F59F0EB3F7B
:1076800008F4B5C0F0E0EE0FFF1FEF50FF4F808110
:107690008093C801E0919F05EF3F59F0EB3F08F45C
:1076A000A3C0F0E0EE0FFF1FEF50FF4F80818093EB
:1076B000C901E091A005EF3F59F0EB3F08F491C0FC
:1076C000F0E0EE0FFF1FEF50FF4F80818093CA0163
:1076D000E091A105EF3F59F0EB3F08F47FC0F0E0E7
:1076E000EE0FFF1FEF50FF4F80818093CB01E091A1
:1076F000A605EF3F59F0EB3F08F46DC0F0E0EE0F48
:10770000FF1FEF50FF4F80818093CC01E091AC05CB
:10771000EF3F59F0EB3F08F453C0F0E0EE0FFF1FCE
:10772000EF50FF4F80818093CE018091CE01823057
:1077300008F44DC08F3F09F486C0E091AE05EF3FDD
:1077400051F0EB3F98F1F0E0EE0FFF1FEF50FF4FCD
:1077500080818093CF018091CF01823068F18F3F8B
:1077600009F474C0E091BF05EF3F29F0EB3F08F04A
:107770005FC0E093CD01DF91CF910895E88366CF9C
:10778000E8834ECF8F3F09F00DCF8093BB010ACF26
:10779000843608F4D2CE84E68093B701CECE843608
:1077A00008F4B5CE84E68093B501B1CEE093CF0165
:1077B0008091CF01823098F681E08093CF01D2CFC3
:1077C000E093CE018091CE01823008F0B3CF81E00A
:1077D0008093CE01B2CFE093CC0198CFE093CB0160
:1077E00086CFE093CA0174CFE093C90162CFE093E2
:1077F000C80150CFE093C7013ECFE093BE01FFCE5A
:10780000E093BA01EDCEE093BC01DBCEE093BB0187
:10781000C1CEE093B901AFCEE093B8019DCEE09325
:10782000B70184CEE093B5016BCEE093B60159CE9B
:10783000F0E0EE0FFF1FEF50FF4F80818093CD01EE
:10784000DF91CF9108958093CE0177CF8093CF01C0
:1078500089CF962F8B3F38F4682F691768F0461749
:1078600070F0862F0895E82FF0E0EE0FFF1FEF5025
:10787000FF4F6081691798F7692F862F0895642F4D
:10788000862F0895CF93DF93ADEDB1E06DE570E005
:107890008C9190E0869FF001879FF00D969FF00DF0
:1078A0001124EB58FA4F408111968C9111974F3F5C
:1078B000E9F04B3F38F0E42FF0E0EE0FFF1FEF5000
:1078C000FF4F408190E0FC01EE0FFF1FEE0FFF1F06
:1078D000EE0FFF1F9F01220F331F220F331FE20FF6
:1078E000F31FE81BF90BEB54FE4F4083129682E026
:1078F000A730B80769F6C7E0D2E099976DE570E068
:10790000888190E0869FF001879FF00D969FF00D93
:107910001124EB58FA4FE0818C91EF3F21F14A811D
:107920009B81EB3F30F0F0E0EE0FFF1FEF50FF4F79
:10793000E081E41720F04E2F9E1708F4492F90E0C5
:10794000FC01EE0FFF1FEE0FFF1FEE0FFF1F9F0149
:10795000220F331F220F331FE20FF31FE81BF90B17
:10796000EB54FE4F40832496129682E0CF31D80725
:1079700039F6ABE5B0E1CBE3D3E0EC91EF3F49F072
:10798000EB3F30F0F0E0EE0FFF1FEF50FF4FE081D4
:10799000E883A35ABF4FA79681E1AF3CB80769F7C8
:1079A000AFE9B7E1C7EDD3E0EC91EF3F49F0EB3F32
:1079B00030F0F0E0EE0FFF1FEF50FF4FE081E88363
:1079C000A35ABF4FA79689E1A331B80769F7DF91A2
:1079D000CF9108958091C800803219F090E0892FEE
:1079E00008958091CA0090E08630C9F791E0892F10
:1079F000089585B18C7F85B9209888EE93E0019732
:107A0000F1F783B190E08370907081309105A9F017
:107A10008230910569F0892BB1F484B1836084B917
:107A20008AE0289A8C3010F0299A089529980895B0
:107A300084B1836084B984E1F4CF84B1836084B974
:107A40008BE02898EFCF84B1836084B98DE02898CB
:107A5000E9CF90935D0280935C02089580910401C8
:107A6000909105018F5F9F4F09F0089588E99AE38F
:107A700090935D0280935C0280E09CE0909305010E
:107A800080930401089580910401909105018F5F16
:107A90009F4F09F008958091910280FFFBCF80E114
:107AA00097E290935D0280935C0280E890E090936F
:107AB000050180930401089580E093E0909305010F
:107AC0008093040180915C0290915D02892B31F4D6
:107AD00080E797E190935D0280935C02089587E0D0
:107AE00090E0909305018093040180915C02909155
:107AF0005D02892B31F480E797E190935D028093DA
:107B00005C0208951F93CF93DF93982F8823C1F0D1
:107B10008091910280FD14C0192F1150C4E6D0E06D
:107B200005C080919102115080FD0AC0D0935D0282
:107B3000C0935C028AEF90E00E949A12112389F7A9
:107B4000DF91CF911F910895DF92EF92FF920F93F3
:107B50001F93CF93DF93EC016091590570915A0503
:107B600080915B0590915C050E94DB217C01609116
:107B70005D0570915E0580915F05909160050E94A2
:107B8000DB21AA2797FDA095BA2F0027F7FC0095C7
:107B9000102FBC01CD01A80197010E94AC41D090EB
:107BA000C1019B01AC012030E0E03E07E0E84E0758
:107BB000E0E05E0778F12150304040485F4F2F5F92
:107BC0003F4F4F47504030F1ED2CFF2400E010E0D4
:107BD0001E2D0027FF24EE242AE030E040E050E094
:107BE0000E942042C801B7010E9420428D2D90E0E2
:107BF000BC01660F771F660F771F660F771F880F10
:107C0000991F680F791F88279927861B970B820F6A
:107C1000931F02C080E090E09C012C0F3D1FC90122
:107C2000DF91CF911F910F91FF90EF90DF9008951A
:107C30000F931F930E94971F182F0E949A1F082FBF
:107C40000E94941F982F8091910280FD05C01230F0
:107C500021F1143009F43FC0163089F0183019F0C2
:107C60001F910F9108951092900210928F028091AF
:107C700091028E7F809391021F910F91089581E070
:107C800090E09093900280938F028091910289609E
:107C9000809391021F910F910895002309F780911D
:107CA000DC018C3010F1299A963018F5892F81501B
:107CB000853078F10E94E5350E948A360E94342F83
:107CC0000E9410350E9405210E94E5350E94823DE8
:107CD0001F910F910895002319F68091DC018C30DB
:107CE00030F0299A0E947217E9CF2998DDCF2998A0
:107CF000F9CF80917D05887209F4B2CF973009F0F1
:107D0000AFCF81E08093A70288EE93E00E94293DE7
:107D1000A7CF892F0E94D435CDCF089595E09093B9
:107D20008D058AE08093A50581E080938905909375
:107D3000A4058EE48093A2058093A305089584B1E1
:107D4000806A84B93D9A82E58CBD1DBC459A8DE65A
:107D500096E090938E0680938D0681E080933306A3
:107D60008AEA80936D0683E880936E068AE08093AA
:107D70006F061092710610927006109273061092A0
:107D800072061092FD021092FC021092FB021092F9
:107D900069068AE480936A0684E680936B0686E02F
:107DA00080936C06089580913306882311F40DB4F6
:107DB00007FE089584E080935E02459A9EB5809107
:107DC0000003813009F458C0813008F039C01092A6
:107DD000F8029093FF02913809F44AC02091FA0208
:107DE000203220F081E0809333060895459800000A
:107DF0000000000000000000000000000000000083
:107E00000000000000000000000000000000000072
:107E10000000000000000000000000000000E091F1
:107E20008D06F0918E06E20FF11D80818EBD90913E
:107E30008C06890F80938C062F5F2093FA02089599
:107E4000823009F0CBCF8091F802E82FF0E0EC5CB3
:107E5000F94F90838F5F8093F8028A31C0F0809150
:107E6000FF029817D1F01092FB0210920003B6CFD8
:107E700081E080930003B2CF9535B9F78091FF027E
:107E80008B5A8093FF0282E080930003A7CF8091FA
:107E9000FF02890F8093FF02A1CFF894AEE4B6E011
:107EA000E4E3F6E08AE101900D928150E1F77894E5
:107EB00081E08093FB02D9CFF894609159057091CD
:107EC0005A0580915B0590915C0529E830E040E01F
:107ED00050E00E942042309371062093700660911A
:107EE0005D0570915E0580915F059091600529E8C0
:107EF00030E040E050E00E9420423093730620932F
:107F000072066091550570915605809157059091C4
:107F100058052AE030E040E050E00E94AC412FEAF2
:107F200034E040E050E00E942042309379062093F4
:107F30007806809165059091660590937B06809305
:107F40007A06809167059091680590937D068093ED
:107F50007C06809153059091540590937F06809301
:107F60007E0680E00E94842829E830E040E050E06E
:107F70000E942042309375062093740681E00E948F
:107F8000842829E830E040E050E00E94204230930D
:107F90007706209376061092B1021092B0021092EA
:107FA000AF021092AE021092AD021092AC0280911C
:107FB0006F068C3009F473C18D3008F460C08D30C9
:107FC00009F41AC18E3009F402C178948091FB0241
:107FD000882309F4D2C020914F0630915006C90180
:107FE00081509E4F8F5F934058F4409151065091BD
:107FF0005206CA0181509E4F8F5F934008F4D7C04C
:10800000809155069091560621E08936920724F416
:108010009093880180938701209187013091880196
:1080200037FD5AC1245E3D4F8091890190918A01AC
:10803000A901481B590BCA0168E671E00E94EB4197
:10804000845B90409093A4028093A30220915906F0
:1080500030915A0680915C0290915D0282179307DD
:1080600040F48091A702882321F430935D0220938D
:108070005C0280914E06873609F488C008958A30E4
:1080800009F4EBC08B3009F0A0CFE0917705F0E068
:10809000EE0FFF1FED5DFA4F0190F081E02D4FEFE5
:1080A000E038F40714F4E0E8FFEFE038F10514F0ED
:1080B000EFE7F0E0E0938006E0917805F0E0EE0F66
:1080C000FF1FED5DFA4F0190F081E02D5FEFE0388A
:1080D000F50714F4E0E8FFEFE038F10514F0EFE7FE
:1080E000F0E0E0938106E0917605F0E0EE0FFF1FEF
:1080F000ED5DFA4F0190F081E02D6FEFE038F6076B
:1081000014F4E0E8FFEFE038F10514F0EFE7F0E0F9
:10811000E0938206E0917505F0E0EE0FFF1FED5D44
:10812000FA4F0190F081E02D8FEFE038F80714F45A
:10813000E0E8FFEFE038F10514F0EFE7F0E0E0935E
:1081400083068091E702809384068091E902809300
:1081500085068091EB02809386068091ED028093E4
:1081600087068091990290919A028093880678946C
:108170008091FB02882309F02ECF1092DA0410922E
:10818000D9041092D8041092D704089580915B0608
:108190008093D90180915C068093DB0180915D061C
:1081A0008093DA0180915E068093FD0208958091AC
:1081B0007D0585FF25CF3093DA042093D9045093B1
:1081C000D8044093D7048AEF8093FC0219CF8091A2
:1081D00069068093800680916A068093810680916B
:1081E0006B068093820680916C0680938306809153
:1081F000DC0180938406E9CE8091AF0580938006F0
:108200008091B005809381068091B10580938206AC
:108210008091B205809383068091B3058093840694
:108220008091B705809385068091B8058093860676
:108230008091B905809387068091BC05809388065C
:108240008091BA05809389068091BB0580938A0648
:108250008091BD0580938B06B8CEEFEBF1E0A0E8EE
:10826000B6E081918D9321E0E73CF207D1F7809150
:1082700091028093880680919102837F809391027E
:1082800080911401909115018093890680918E054B
:1082900080938A060E94E53580938B0696CE809166
:1082A000A70280938006853010F01092A70280917B
:1082B000BE058093810610928306109282068091FB
:1082C000B405809384068091B505809385068091DE
:1082D000B6058093860679CE1092A4021092A3026E
:1082E000B5CE80913306882309F435C04598809136
:1082F000FE02E82FF0E0E75DFD4F908190936F065E
:108300008F5F8093FE02863010F01092FE02109272
:1083100033060E945C3F81E08093FA020000000077
:10832000000000000000000000000000000000004D
:10833000000000000000000000000000000000003D
:1083400000000000000000000000000080916D06A9
:1083500080938C068EBD0895629FD001739FF001BB
:10836000829FE00DF11D649FE00DF11D929FF00DC5
:10837000839FF00D749FF00D659FF00D9927729FFC
:10838000B00DE11DF91F639FB00DE11DF91FBD0187
:10839000CF0111240895991B79E004C0991F961705
:1083A00008F0961B881F7A95C9F780950895AA1B37
:1083B000BB1B51E107C0AA1FBB1FA617B70710F0D0
:1083C000A61BB70B881F991F5A95A9F78095909502
:1083D000BC01CD01089597FB092E07260AD077FD31
:1083E00004D0E5DF06D000201AF4709561957F4F28
:1083F0000895F6F7909581959F4F0895A1E21A2E62
:10840000AA1BBB1BFD010DC0AA1FBB1FEE1FFF1F38
:10841000A217B307E407F50720F0A21BB30BE40B88
:10842000F50B661F771F881F991F1A9469F76095CF
:108430007095809590959B01AC01BD01CF01089589
:1084400097FB092E05260ED057FD04D0D7DF0AD0A2
:10845000001C38F450954095309521953F4F4F4F73
:108460005F4F0895F6F790958095709561957F4FD1
:108470008F4F9F4F0895FB01DC0102C005900D92C4
:1084800041505040D8F70895FC014150504030F021
:1084900001900616D1F73197CF01089588279927C3
:1084A0000895DC01CB01FC01F999FECF06C0F2BDB5
:1084B000E1BDF89A319600B40D9241505040B8F7A2
:1084C0000895F999FECF92BD81BDF89A992780B59C
:1084D0000895A8E1B0E042E050E00C945342DC0182
:1084E000CB0103C02D910E947A4241505040D0F7F9
:1084F0000895262FF999FECF1FBA92BD81BD20BDE8
:108500000FB6F894FA9AF99A0FBE019608950E9450
:0C8510007942272F0C947A42F894FFCF98
:10851C00FF01F401FFFF0100080008000400040043
:10852C000400026A6400010000000000000000006A
:10853C000000000000000000000000000000001916
:10854C0000020D48656C6C6F20576F726C640000F4
:10855C00000000000000000000000000000000000F
:10856C0000000000000000000000000000000000FF
:10857C0000000000000000000000000000000000EF
:10858C0000000000000000000000000000000000DF
:10859C0000000064000101FFFFFFFFF4010001383F
:1085AC00010151756164726F0000426567696E6EFE
:1085BC00657200004E6F726D616C000053706F72CB
:1085CC00740000320030FB103A40089696020A0004
:1085DC000000000000000064465A414064000000A6
:1085EC000000000000000000000000000D0B010E58
:1085FC00031504170718051D09221227132A142B1B
:10860C00152C1631173A1B3B1C3C1D3D1E3E1F42C0
:10861C0020452246234A180A0000640C00009616D6
:10862C000600FF371901FF391A01FF47210AFF0025
:10863C000080000000000001000A0B0D0B0C0E0066
:00000001FF
/branches/dongfang_FC_rewrite/GPSControl.c
4,5 → 4,5
int16_t GPSStickPitch, GPSStickRoll;
 
void GPS_setNeutral(void) {
GPSStickPitch = GPSStickRoll = 0;
GPSStickPitch = GPSStickRoll = 0;
}
/branches/dongfang_FC_rewrite/analog.c
77,7 → 77,7
*/
volatile int16_t rawGyroSum[3];
volatile int16_t acc[3];
volatile int16_t filteredAcc[2]={0,0};
volatile int16_t filteredAcc[2] = { 0, 0 };
 
/*
* These 4 exported variables are zero-offset. The "PID" ones are used
94,17 → 94,11
* standing still. They are used for adjusting the gyro and acc. meter values
* to be centered on zero.
*/
volatile int16_t gyroOffset[3] = {
512 * GYRO_SUMMATION_FACTOR_PITCHROLL,
512 * GYRO_SUMMATION_FACTOR_PITCHROLL,
512 * GYRO_SUMMATION_FACTOR_YAW
};
volatile int16_t gyroOffset[3] = { 512 * GYRO_SUMMATION_FACTOR_PITCHROLL, 512
* GYRO_SUMMATION_FACTOR_PITCHROLL, 512 * GYRO_SUMMATION_FACTOR_YAW };
 
volatile int16_t accOffset[3] = {
512 * ACC_SUMMATION_FACTOR_PITCHROLL,
512 * ACC_SUMMATION_FACTOR_PITCHROLL,
512 * ACC_SUMMATION_FACTOR_Z
};
volatile int16_t accOffset[3] = { 512 * ACC_SUMMATION_FACTOR_PITCHROLL, 512
* ACC_SUMMATION_FACTOR_PITCHROLL, 512 * ACC_SUMMATION_FACTOR_Z };
 
/*
* This allows some experimentation with the gyro filters.
176,72 → 170,66
* at all. The cost is not significant.
*/
 
const uint8_t channelsForStates[] PROGMEM = {
AD_GYRO_PITCH,
AD_GYRO_ROLL,
AD_GYRO_YAW,
const uint8_t channelsForStates[] PROGMEM = { AD_GYRO_PITCH, AD_GYRO_ROLL,
AD_GYRO_YAW,
 
AD_ACC_PITCH,
AD_ACC_ROLL,
AD_AIRPRESSURE,
AD_GYRO_PITCH,
AD_GYRO_ROLL,
AD_ACC_Z, // at 8, measure Z acc.
AD_ACC_PITCH, AD_ACC_ROLL, AD_AIRPRESSURE,
 
AD_GYRO_PITCH,
AD_GYRO_ROLL,
AD_GYRO_YAW, // at 11, finish yaw gyro
AD_GYRO_PITCH, AD_GYRO_ROLL, AD_ACC_Z, // at 8, measure Z acc.
 
AD_ACC_PITCH, // at 12, finish pitch axis acc.
AD_ACC_ROLL, // at 13, finish roll axis acc.
AD_AIRPRESSURE, // at 14, finish air pressure.
AD_GYRO_PITCH, AD_GYRO_ROLL, AD_GYRO_YAW, // at 11, finish yaw gyro
 
AD_GYRO_PITCH, // at 15, finish pitch gyro
AD_GYRO_ROLL, // at 16, finish roll gyro
AD_UBAT // at 17, measure battery.
};
AD_ACC_PITCH, // at 12, finish pitch axis acc.
AD_ACC_ROLL, // at 13, finish roll axis acc.
AD_AIRPRESSURE, // at 14, finish air pressure.
 
AD_GYRO_PITCH, // at 15, finish pitch gyro
AD_GYRO_ROLL, // at 16, finish roll gyro
AD_UBAT // at 17, measure battery.
};
 
// Feature removed. Could be reintroduced later - but should work for all gyro types then.
// uint8_t GyroDefectPitch = 0, GyroDefectRoll = 0, GyroDefectYaw = 0;
 
void analog_init(void) {
uint8_t sreg = SREG;
// disable all interrupts before reconfiguration
cli();
uint8_t sreg = SREG;
// disable all interrupts before reconfiguration
cli();
 
//ADC0 ... ADC7 is connected to PortA pin 0 ... 7
DDRA = 0x00;
PORTA = 0x00;
// Digital Input Disable Register 0
// Disable digital input buffer for analog adc_channel pins
DIDR0 = 0xFF;
// external reference, adjust data to the right
ADMUX &= ~((1 << REFS1)|(1 << REFS0)|(1 << ADLAR));
// set muxer to ADC adc_channel 0 (0 to 7 is a valid choice)
ADMUX = (ADMUX & 0xE0) | AD_GYRO_PITCH;
//Set ADC Control and Status Register A
//Auto Trigger Enable, Prescaler Select Bits to Division Factor 128, i.e. ADC clock = SYSCKL/128 = 156.25 kHz
ADCSRA = (0<<ADEN)|(0<<ADSC)|(0<<ADATE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(0<<ADIE);
//Set ADC Control and Status Register B
//Trigger Source to Free Running Mode
ADCSRB &= ~((1 << ADTS2)|(1 << ADTS1)|(1 << ADTS0));
// Start AD conversion
analog_start();
// restore global interrupt flags
SREG = sreg;
//ADC0 ... ADC7 is connected to PortA pin 0 ... 7
DDRA = 0x00;
PORTA = 0x00;
// Digital Input Disable Register 0
// Disable digital input buffer for analog adc_channel pins
DIDR0 = 0xFF;
// external reference, adjust data to the right
ADMUX &= ~((1 << REFS1) | (1 << REFS0) | (1 << ADLAR));
// set muxer to ADC adc_channel 0 (0 to 7 is a valid choice)
ADMUX = (ADMUX & 0xE0) | AD_GYRO_PITCH;
//Set ADC Control and Status Register A
//Auto Trigger Enable, Prescaler Select Bits to Division Factor 128, i.e. ADC clock = SYSCKL/128 = 156.25 kHz
ADCSRA = (0 << ADEN) | (0 << ADSC) | (0 << ADATE) | (1 << ADPS2) | (1
<< ADPS1) | (1 << ADPS0) | (0 << ADIE);
//Set ADC Control and Status Register B
//Trigger Source to Free Running Mode
ADCSRB &= ~((1 << ADTS2) | (1 << ADTS1) | (1 << ADTS0));
// Start AD conversion
analog_start();
// restore global interrupt flags
SREG = sreg;
}
 
void measureNoise(const int16_t sensor, volatile uint16_t* const noiseMeasurement, const uint8_t damping) {
if (sensor > (int16_t)(*noiseMeasurement)) {
*noiseMeasurement = sensor;
} else if (-sensor > (int16_t)(*noiseMeasurement)) {
*noiseMeasurement = -sensor;
} else if (*noiseMeasurement > damping) {
*noiseMeasurement -= damping;
} else {
*noiseMeasurement = 0;
}
void measureNoise(const int16_t sensor,
volatile uint16_t* const noiseMeasurement, const uint8_t damping) {
if (sensor > (int16_t) (*noiseMeasurement)) {
*noiseMeasurement = sensor;
} else if (-sensor > (int16_t) (*noiseMeasurement)) {
*noiseMeasurement = -sensor;
} else if (*noiseMeasurement > damping) {
*noiseMeasurement -= damping;
} else {
*noiseMeasurement = 0;
}
}
 
/*
249,7 → 237,7
* Max: About 106 * 240 + 2047 = 27487; it is OK with just a 16 bit type.
*/
uint16_t getSimplePressure(int advalue) {
return (uint16_t)OCR0A * (uint16_t)rangewidth + advalue;
return (uint16_t) OCR0A * (uint16_t) rangewidth + advalue;
}
 
/*****************************************************
258,247 → 246,262
* processed the interrupt is disabled and further
* AD conversions are stopped.
*****************************************************/
ISR(ADC_vect) {
static uint8_t ad_channel = AD_GYRO_PITCH, state = 0;
static uint16_t sensorInputs[8] = {0,0,0,0,0,0,0,0};
static uint16_t pressureAutorangingWait = 25;
uint16_t rawAirPressure;
uint8_t i, axis;
int16_t newrange;
// for various filters...
int16_t tempOffsetGyro, tempGyro;
sensorInputs[ad_channel] += ADC;
ISR(ADC_vect)
{
static uint8_t ad_channel = AD_GYRO_PITCH, state = 0;
static uint16_t sensorInputs[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
static uint16_t pressureAutorangingWait = 25;
uint16_t rawAirPressure;
uint8_t i, axis;
int16_t newrange;
 
/*
* Actually we don't need this "switch". We could do all the sampling into the
* sensorInputs array first, and all the processing after the last sample.
*/
switch(state++) {
// for various filters...
int16_t tempOffsetGyro, tempGyro;
 
case 8: // Z acc
if (ACC_REVERSED[Z])
acc[Z] = accOffset[Z] - sensorInputs[AD_ACC_Z];
else
acc[Z] = sensorInputs[AD_ACC_Z] - accOffset[Z];
break;
case 11: // yaw gyro
rawGyroSum[YAW] = sensorInputs[AD_GYRO_YAW];
if (GYRO_REVERSED[YAW])
yawGyro = gyroOffset[YAW] - sensorInputs[AD_GYRO_YAW];
else
yawGyro = sensorInputs[AD_GYRO_YAW] - gyroOffset[YAW];
break;
case 12: // pitch axis acc.
if (ACC_REVERSED[PITCH])
acc[PITCH] = accOffset[PITCH] - sensorInputs[AD_ACC_PITCH];
else
acc[PITCH] = sensorInputs[AD_ACC_PITCH] - accOffset[PITCH];
sensorInputs[ad_channel] += ADC;
 
filteredAcc[PITCH] = (filteredAcc[PITCH] * (ACC_FILTER-1) + acc[PITCH]) / ACC_FILTER;
measureNoise(acc[PITCH], &accNoisePeak[PITCH], 1);
break;
case 13: // roll axis acc.
if (ACC_REVERSED[ROLL])
acc[ROLL] = accOffset[ROLL] - sensorInputs[AD_ACC_ROLL];
else
acc[ROLL] = sensorInputs[AD_ACC_ROLL] - accOffset[ROLL];
filteredAcc[ROLL] = (filteredAcc[ROLL] * (ACC_FILTER-1) + acc[ROLL]) / ACC_FILTER;
measureNoise(acc[ROLL], &accNoisePeak[ROLL], 1);
break;
/*
* Actually we don't need this "switch". We could do all the sampling into the
* sensorInputs array first, and all the processing after the last sample.
*/
switch (state++) {
 
case 14: // air pressure
if (pressureAutorangingWait) {
//A range switch was done recently. Wait for steadying.
pressureAutorangingWait--;
DebugOut.Analog[27] = (uint16_t)OCR0A;
DebugOut.Analog[31] = simpleAirPressure;
break;
}
case 8: // Z acc
if (ACC_REVERSED[Z])
acc[Z] = accOffset[Z] - sensorInputs[AD_ACC_Z];
else
acc[Z] = sensorInputs[AD_ACC_Z] - accOffset[Z];
break;
 
rawAirPressure = sensorInputs[AD_AIRPRESSURE];
if (rawAirPressure < MIN_RAWPRESSURE) {
// value is too low, so decrease voltage on the op amp minus input, making the value higher.
newrange = OCR0A - (MAX_RAWPRESSURE - MIN_RAWPRESSURE) / (rangewidth * 4); // 4; // (MAX_RAWPRESSURE - rawAirPressure) / (rangewidth * 2) + 1;
if (newrange > MIN_RANGES_EXTRAPOLATION) {
pressureAutorangingWait = (OCR0A - newrange) * AUTORANGE_WAIT_FACTOR; // = OCRA0 - OCRA0 +
OCR0A = newrange;
} else {
if (OCR0A) {
OCR0A--;
pressureAutorangingWait = AUTORANGE_WAIT_FACTOR;
}
}
} else if (rawAirPressure > MAX_RAWPRESSURE) {
// value is too high, so increase voltage on the op amp minus input, making the value lower.
// If near the end, make a limited increase
newrange = OCR0A + (MAX_RAWPRESSURE - MIN_RAWPRESSURE) / (rangewidth * 4); // 4; // (rawAirPressure - MIN_RAWPRESSURE) / (rangewidth * 2) - 1;
if (newrange < MAX_RANGES_EXTRAPOLATION) {
pressureAutorangingWait = (newrange - OCR0A) * AUTORANGE_WAIT_FACTOR;
OCR0A = newrange;
} else {
if (OCR0A<254) {
OCR0A++;
pressureAutorangingWait = AUTORANGE_WAIT_FACTOR;
}
}
}
case 11: // yaw gyro
rawGyroSum[YAW] = sensorInputs[AD_GYRO_YAW];
if (GYRO_REVERSED[YAW])
yawGyro = gyroOffset[YAW] - sensorInputs[AD_GYRO_YAW];
else
yawGyro = sensorInputs[AD_GYRO_YAW] - gyroOffset[YAW];
break;
 
// Even if the sample is off-range, use it.
simpleAirPressure = getSimplePressure(rawAirPressure);
DebugOut.Analog[27] = (uint16_t)OCR0A;
DebugOut.Analog[31] = simpleAirPressure;
case 12: // pitch axis acc.
if (ACC_REVERSED[PITCH])
acc[PITCH] = accOffset[PITCH] - sensorInputs[AD_ACC_PITCH];
else
acc[PITCH] = sensorInputs[AD_ACC_PITCH] - accOffset[PITCH];
 
if (simpleAirPressure < MIN_RANGES_EXTRAPOLATION * rangewidth) {
// Danger: pressure near lower end of range. If the measurement saturates, the
// copter may climb uncontrolledly... Simulate a drastic reduction in pressure.
airPressureSum += (int16_t)MIN_RANGES_EXTRAPOLATION * rangewidth + (simpleAirPressure - (int16_t)MIN_RANGES_EXTRAPOLATION * rangewidth) * PRESSURE_EXTRAPOLATION_COEFF;
} else if (simpleAirPressure > MAX_RANGES_EXTRAPOLATION * rangewidth) {
// Danger: pressure near upper end of range. If the measurement saturates, the
// copter may descend uncontrolledly... Simulate a drastic increase in pressure.
airPressureSum += (int16_t)MAX_RANGES_EXTRAPOLATION * rangewidth + (simpleAirPressure - (int16_t)MAX_RANGES_EXTRAPOLATION * rangewidth) * PRESSURE_EXTRAPOLATION_COEFF;
} else {
// normal case.
// If AIRPRESSURE_SUMMATION_FACTOR is an odd number we only want to add half the double sample.
// The 2 cases above (end of range) are ignored for this.
if (pressureMeasurementCount == AIRPRESSURE_SUMMATION_FACTOR - 1)
airPressureSum += simpleAirPressure / 2;
else
airPressureSum += simpleAirPressure;
}
filteredAcc[PITCH] = (filteredAcc[PITCH] * (ACC_FILTER - 1) + acc[PITCH])
/ ACC_FILTER;
measureNoise(acc[PITCH], &accNoisePeak[PITCH], 1);
break;
 
// 2 samples were added.
pressureMeasurementCount += 2;
if (pressureMeasurementCount >= AIRPRESSURE_SUMMATION_FACTOR) {
filteredAirPressure = (filteredAirPressure * (AIRPRESSURE_FILTER-1) + airPressureSum + AIRPRESSURE_FILTER/2) / AIRPRESSURE_FILTER;
pressureMeasurementCount = airPressureSum = 0;
}
case 13: // roll axis acc.
if (ACC_REVERSED[ROLL])
acc[ROLL] = accOffset[ROLL] - sensorInputs[AD_ACC_ROLL];
else
acc[ROLL] = sensorInputs[AD_ACC_ROLL] - accOffset[ROLL];
filteredAcc[ROLL] = (filteredAcc[ROLL] * (ACC_FILTER - 1) + acc[ROLL])
/ ACC_FILTER;
measureNoise(acc[ROLL], &accNoisePeak[ROLL], 1);
break;
 
break;
case 14: // air pressure
if (pressureAutorangingWait) {
//A range switch was done recently. Wait for steadying.
pressureAutorangingWait--;
DebugOut.Analog[27] = (uint16_t) OCR0A;
DebugOut.Analog[31] = simpleAirPressure;
break;
}
 
case 15:
case 16: // pitch or roll gyro.
axis = state - 16;
tempGyro = rawGyroSum[axis] = sensorInputs[AD_GYRO_PITCH - axis];
// DebugOut.Analog[6 + 3 * axis ] = tempGyro;
/*
* Process the gyro data for the PID controller.
*/
// 1) Extrapolate: Near the ends of the range, we boost the input significantly. This simulates a
// gyro with a wider range, and helps counter saturation at full control.
rawAirPressure = sensorInputs[AD_AIRPRESSURE];
if (rawAirPressure < MIN_RAWPRESSURE) {
// value is too low, so decrease voltage on the op amp minus input, making the value higher.
newrange = OCR0A - (MAX_RAWPRESSURE - MIN_RAWPRESSURE) / (rangewidth * 4); // 4; // (MAX_RAWPRESSURE - rawAirPressure) / (rangewidth * 2) + 1;
if (newrange > MIN_RANGES_EXTRAPOLATION) {
pressureAutorangingWait = (OCR0A - newrange) * AUTORANGE_WAIT_FACTOR; // = OCRA0 - OCRA0 +
OCR0A = newrange;
} else {
if (OCR0A) {
OCR0A--;
pressureAutorangingWait = AUTORANGE_WAIT_FACTOR;
}
}
} else if (rawAirPressure > MAX_RAWPRESSURE) {
// value is too high, so increase voltage on the op amp minus input, making the value lower.
// If near the end, make a limited increase
newrange = OCR0A + (MAX_RAWPRESSURE - MIN_RAWPRESSURE) / (rangewidth * 4); // 4; // (rawAirPressure - MIN_RAWPRESSURE) / (rangewidth * 2) - 1;
if (newrange < MAX_RANGES_EXTRAPOLATION) {
pressureAutorangingWait = (newrange - OCR0A) * AUTORANGE_WAIT_FACTOR;
OCR0A = newrange;
} else {
if (OCR0A < 254) {
OCR0A++;
pressureAutorangingWait = AUTORANGE_WAIT_FACTOR;
}
}
}
 
if (staticParams.GlobalConfig & CFG_ROTARY_RATE_LIMITER) {
if (tempGyro < SENSOR_MIN_PITCHROLL) {
tempGyro = tempGyro * EXTRAPOLATION_SLOPE - EXTRAPOLATION_LIMIT;
}
else if (tempGyro > SENSOR_MAX_PITCHROLL) {
tempGyro = (tempGyro - SENSOR_MAX_PITCHROLL) * EXTRAPOLATION_SLOPE + SENSOR_MAX_PITCHROLL;
}
}
// Even if the sample is off-range, use it.
simpleAirPressure = getSimplePressure(rawAirPressure);
DebugOut.Analog[27] = (uint16_t) OCR0A;
DebugOut.Analog[31] = simpleAirPressure;
 
// 2) Apply sign and offset, scale before filtering.
if (GYRO_REVERSED[axis]) {
tempOffsetGyro = (gyroOffset[axis] - tempGyro) * GYRO_FACTOR_PITCHROLL;
} else {
tempOffsetGyro = (tempGyro - gyroOffset[axis]) * GYRO_FACTOR_PITCHROLL;
}
if (simpleAirPressure < MIN_RANGES_EXTRAPOLATION * rangewidth) {
// Danger: pressure near lower end of range. If the measurement saturates, the
// copter may climb uncontrolledly... Simulate a drastic reduction in pressure.
airPressureSum += (int16_t) MIN_RANGES_EXTRAPOLATION * rangewidth
+ (simpleAirPressure - (int16_t) MIN_RANGES_EXTRAPOLATION
* rangewidth) * PRESSURE_EXTRAPOLATION_COEFF;
} else if (simpleAirPressure > MAX_RANGES_EXTRAPOLATION * rangewidth) {
// Danger: pressure near upper end of range. If the measurement saturates, the
// copter may descend uncontrolledly... Simulate a drastic increase in pressure.
airPressureSum += (int16_t) MAX_RANGES_EXTRAPOLATION * rangewidth
+ (simpleAirPressure - (int16_t) MAX_RANGES_EXTRAPOLATION
* rangewidth) * PRESSURE_EXTRAPOLATION_COEFF;
} else {
// normal case.
// If AIRPRESSURE_SUMMATION_FACTOR is an odd number we only want to add half the double sample.
// The 2 cases above (end of range) are ignored for this.
if (pressureMeasurementCount == AIRPRESSURE_SUMMATION_FACTOR - 1)
airPressureSum += simpleAirPressure / 2;
else
airPressureSum += simpleAirPressure;
}
 
// 3) Scale and filter.
tempOffsetGyro = (gyro_PID[axis] * (GYROS_PID_FILTER-1) + tempOffsetGyro) / GYROS_PID_FILTER;
// 2 samples were added.
pressureMeasurementCount += 2;
if (pressureMeasurementCount >= AIRPRESSURE_SUMMATION_FACTOR) {
filteredAirPressure = (filteredAirPressure * (AIRPRESSURE_FILTER - 1)
+ airPressureSum + AIRPRESSURE_FILTER / 2) / AIRPRESSURE_FILTER;
pressureMeasurementCount = airPressureSum = 0;
}
 
// 4) Measure noise.
measureNoise(tempOffsetGyro, &gyroNoisePeak[axis], GYRO_NOISE_MEASUREMENT_DAMPING);
break;
 
// 5) Differential measurement.
gyroD[axis] = (gyroD[axis] * (GYROS_D_FILTER-1) + (tempOffsetGyro - gyro_PID[axis])) / GYROS_D_FILTER;
case 15:
case 16: // pitch or roll gyro.
axis = state - 16;
tempGyro = rawGyroSum[axis] = sensorInputs[AD_GYRO_PITCH - axis];
// DebugOut.Analog[6 + 3 * axis ] = tempGyro;
/*
* Process the gyro data for the PID controller.
*/
// 1) Extrapolate: Near the ends of the range, we boost the input significantly. This simulates a
// gyro with a wider range, and helps counter saturation at full control.
 
// 6) Done.
gyro_PID[axis] = tempOffsetGyro;
if (staticParams.GlobalConfig & CFG_ROTARY_RATE_LIMITER) {
if (tempGyro < SENSOR_MIN_PITCHROLL) {
tempGyro = tempGyro * EXTRAPOLATION_SLOPE - EXTRAPOLATION_LIMIT;
} else if (tempGyro > SENSOR_MAX_PITCHROLL) {
tempGyro = (tempGyro - SENSOR_MAX_PITCHROLL) * EXTRAPOLATION_SLOPE
+ SENSOR_MAX_PITCHROLL;
}
}
 
/*
* Now process the data for attitude angles.
*/
tempGyro = rawGyroSum[axis];
// 1) Apply sign and offset, scale before filtering.
if (GYRO_REVERSED[axis]) {
tempOffsetGyro = (gyroOffset[axis] - tempGyro) * GYRO_FACTOR_PITCHROLL;
} else {
tempOffsetGyro = (tempGyro - gyroOffset[axis]) * GYRO_FACTOR_PITCHROLL;
}
// 2) Filter.
gyro_ATT[axis] = (gyro_ATT[axis] * (GYROS_ATT_FILTER-1) + tempOffsetGyro) / GYROS_ATT_FILTER;
break;
case 17:
// Battery. The measured value is: (V * 1k/11k)/3v * 1024 = 31.03 counts per volt (max. measurable is 33v).
// This is divided by 3 --> 10.34 counts per volt.
UBat = (3 * UBat + sensorInputs[AD_UBAT] / 3) / 4;
DebugOut.Analog[11] = UBat;
analogDataReady = 1; // mark
ADCycleCount++;
// Stop the sampling. Cycle is over.
state = 0;
for (i=0; i<8; i++) {
sensorInputs[i] = 0;
}
break;
default: {} // do nothing.
}
// 2) Apply sign and offset, scale before filtering.
if (GYRO_REVERSED[axis]) {
tempOffsetGyro = (gyroOffset[axis] - tempGyro) * GYRO_FACTOR_PITCHROLL;
} else {
tempOffsetGyro = (tempGyro - gyroOffset[axis]) * GYRO_FACTOR_PITCHROLL;
}
 
// set up for next state.
ad_channel = pgm_read_byte(&channelsForStates[state]);
// ad_channel = channelsForStates[state];
// set adc muxer to next ad_channel
ADMUX = (ADMUX & 0xE0) | ad_channel;
// after full cycle stop further interrupts
if(state) analog_start();
// 3) Scale and filter.
tempOffsetGyro = (gyro_PID[axis] * (GYROS_PID_FILTER - 1) + tempOffsetGyro)
/ GYROS_PID_FILTER;
 
// 4) Measure noise.
measureNoise(tempOffsetGyro, &gyroNoisePeak[axis],
GYRO_NOISE_MEASUREMENT_DAMPING);
 
// 5) Differential measurement.
gyroD[axis] = (gyroD[axis] * (GYROS_D_FILTER - 1) + (tempOffsetGyro
- gyro_PID[axis])) / GYROS_D_FILTER;
 
// 6) Done.
gyro_PID[axis] = tempOffsetGyro;
 
/*
* Now process the data for attitude angles.
*/
tempGyro = rawGyroSum[axis];
 
// 1) Apply sign and offset, scale before filtering.
if (GYRO_REVERSED[axis]) {
tempOffsetGyro = (gyroOffset[axis] - tempGyro) * GYRO_FACTOR_PITCHROLL;
} else {
tempOffsetGyro = (tempGyro - gyroOffset[axis]) * GYRO_FACTOR_PITCHROLL;
}
 
// 2) Filter.
gyro_ATT[axis] = (gyro_ATT[axis] * (GYROS_ATT_FILTER - 1) + tempOffsetGyro)
/ GYROS_ATT_FILTER;
break;
 
case 17:
// Battery. The measured value is: (V * 1k/11k)/3v * 1024 = 31.03 counts per volt (max. measurable is 33v).
// This is divided by 3 --> 10.34 counts per volt.
UBat = (3 * UBat + sensorInputs[AD_UBAT] / 3) / 4;
DebugOut.Analog[11] = UBat;
analogDataReady = 1; // mark
ADCycleCount++;
// Stop the sampling. Cycle is over.
state = 0;
for (i = 0; i < 8; i++) {
sensorInputs[i] = 0;
}
break;
default: {
} // do nothing.
}
 
// set up for next state.
ad_channel = pgm_read_byte(&channelsForStates[state]);
// ad_channel = channelsForStates[state];
 
// set adc muxer to next ad_channel
ADMUX = (ADMUX & 0xE0) | ad_channel;
// after full cycle stop further interrupts
if (state)
analog_start();
}
 
void analog_calibrate(void) {
#define GYRO_OFFSET_CYCLES 32
uint8_t i, axis;
int32_t deltaOffsets[3] = {0,0,0};
uint8_t i, axis;
int32_t deltaOffsets[3] = { 0, 0, 0 };
 
// Set the filters... to be removed again, once some good settings are found.
GYROS_PID_FILTER = (dynamicParams.UserParams[4] & 0b00000011) + 1;
GYROS_ATT_FILTER = ((dynamicParams.UserParams[4] & 0b00001100) >> 2) + 1;
GYROS_D_FILTER = ((dynamicParams.UserParams[4] & 0b00110000) >> 4) + 1;
ACC_FILTER = ((dynamicParams.UserParams[4] & 0b11000000) >> 6) + 1;
// Set the filters... to be removed again, once some good settings are found.
GYROS_PID_FILTER = (dynamicParams.UserParams[4] & 0b00000011) + 1;
GYROS_ATT_FILTER = ((dynamicParams.UserParams[4] & 0b00001100) >> 2) + 1;
GYROS_D_FILTER = ((dynamicParams.UserParams[4] & 0b00110000) >> 4) + 1;
ACC_FILTER = ((dynamicParams.UserParams[4] & 0b11000000) >> 6) + 1;
 
gyro_calibrate();
gyro_calibrate();
 
// determine gyro bias by averaging (requires that the copter does not rotate around any axis!)
for(i=0; i < GYRO_OFFSET_CYCLES; i++) {
Delay_ms_Mess(20);
for (axis=PITCH; axis<=YAW; axis++) {
deltaOffsets[axis] += rawGyroSum[axis];
}
}
// determine gyro bias by averaging (requires that the copter does not rotate around any axis!)
for (i = 0; i < GYRO_OFFSET_CYCLES; i++) {
Delay_ms_Mess(20);
for (axis = PITCH; axis <= YAW; axis++) {
deltaOffsets[axis] += rawGyroSum[axis];
}
}
 
for (axis=PITCH; axis<=YAW; axis++) {
gyroOffset[axis] = (deltaOffsets[axis] + GYRO_OFFSET_CYCLES/2) / GYRO_OFFSET_CYCLES;
DebugOut.Analog[20+axis] = gyroOffset[axis];
}
for (axis = PITCH; axis <= YAW; axis++) {
gyroOffset[axis] = (deltaOffsets[axis] + GYRO_OFFSET_CYCLES / 2)
/ GYRO_OFFSET_CYCLES;
DebugOut.Analog[20 + axis] = gyroOffset[axis];
}
 
// Noise is relative to offset. So, reset noise measurements when changing offsets.
gyroNoisePeak[PITCH] = gyroNoisePeak[ROLL] = 0;
// Noise is relative to offset. So, reset noise measurements when changing offsets.
gyroNoisePeak[PITCH] = gyroNoisePeak[ROLL] = 0;
 
accOffset[PITCH] = GetParamWord(PID_ACC_PITCH);
accOffset[ROLL] = GetParamWord(PID_ACC_ROLL);
accOffset[Z] = GetParamWord(PID_ACC_Z);
accOffset[PITCH] = GetParamWord(PID_ACC_PITCH);
accOffset[ROLL] = GetParamWord(PID_ACC_ROLL);
accOffset[Z] = GetParamWord(PID_ACC_Z);
 
// Rough estimate. Hmm no nothing happens at calibration anyway.
// airPressureSum = simpleAirPressure * (AIRPRESSURE_SUMMATION_FACTOR/2);
// pressureMeasurementCount = 0;
// Rough estimate. Hmm no nothing happens at calibration anyway.
// airPressureSum = simpleAirPressure * (AIRPRESSURE_SUMMATION_FACTOR/2);
// pressureMeasurementCount = 0;
 
Delay_ms_Mess(100);
Delay_ms_Mess(100);
}
 
/*
510,60 → 513,61
*/
void analog_calibrateAcc(void) {
#define ACC_OFFSET_CYCLES 10
uint8_t i, axis;
int32_t deltaOffset[3] = {0,0,0};
int16_t filteredDelta;
// int16_t pressureDiff, savedRawAirPressure;
uint8_t i, axis;
int32_t deltaOffset[3] = { 0, 0, 0 };
int16_t filteredDelta;
// int16_t pressureDiff, savedRawAirPressure;
 
for(i=0; i < ACC_OFFSET_CYCLES; i++) {
Delay_ms_Mess(10);
for (axis=PITCH; axis<=YAW; axis++) {
deltaOffset[axis] += acc[axis];
}
}
for (i = 0; i < ACC_OFFSET_CYCLES; i++) {
Delay_ms_Mess(10);
for (axis = PITCH; axis <= YAW; axis++) {
deltaOffset[axis] += acc[axis];
}
}
 
for (axis=PITCH; axis<=YAW; axis++) {
filteredDelta = (deltaOffset[axis] + ACC_OFFSET_CYCLES / 2) / ACC_OFFSET_CYCLES;
accOffset[axis] += ACC_REVERSED[axis] ? -filteredDelta : filteredDelta;
}
for (axis = PITCH; axis <= YAW; axis++) {
filteredDelta = (deltaOffset[axis] + ACC_OFFSET_CYCLES / 2)
/ ACC_OFFSET_CYCLES;
accOffset[axis] += ACC_REVERSED[axis] ? -filteredDelta : filteredDelta;
}
 
// Save ACC neutral settings to eeprom
SetParamWord(PID_ACC_PITCH, accOffset[PITCH]);
SetParamWord(PID_ACC_ROLL, accOffset[ROLL]);
SetParamWord(PID_ACC_Z, accOffset[Z]);
// Save ACC neutral settings to eeprom
SetParamWord(PID_ACC_PITCH, accOffset[PITCH]);
SetParamWord(PID_ACC_ROLL, accOffset[ROLL]);
SetParamWord(PID_ACC_Z, accOffset[Z]);
 
// Noise is relative to offset. So, reset noise measurements when
// changing offsets.
accNoisePeak[PITCH] = accNoisePeak[ROLL] = 0;
// Setting offset values has an influence in the analog.c ISR
// Therefore run measurement for 100ms to achive stable readings
Delay_ms_Mess(100);
// Set the feedback so that air pressure ends up in the middle of the range.
// (raw pressure high --> OCR0A also high...)
/*
OCR0A += ((rawAirPressure - 1024) / rangewidth) - 1;
Delay_ms_Mess(1000);
// Noise is relative to offset. So, reset noise measurements when
// changing offsets.
accNoisePeak[PITCH] = accNoisePeak[ROLL] = 0;
 
pressureDiff = 0;
// DebugOut.Analog[16] = rawAirPressure;
#define PRESSURE_CAL_CYCLE_COUNT 5
for (i=0; i<PRESSURE_CAL_CYCLE_COUNT; i++) {
savedRawAirPressure = rawAirPressure;
OCR0A+=2;
Delay_ms_Mess(500);
// raw pressure will decrease.
pressureDiff += (savedRawAirPressure - rawAirPressure);
savedRawAirPressure = rawAirPressure;
OCR0A-=2;
Delay_ms_Mess(500);
// raw pressure will increase.
pressureDiff += (rawAirPressure - savedRawAirPressure);
}
rangewidth = (pressureDiff + PRESSURE_CAL_CYCLE_COUNT * 2 * 2 - 1) / (PRESSURE_CAL_CYCLE_COUNT * 2 * 2);
DebugOut.Analog[27] = rangewidth;
*/
// Setting offset values has an influence in the analog.c ISR
// Therefore run measurement for 100ms to achive stable readings
Delay_ms_Mess(100);
 
// Set the feedback so that air pressure ends up in the middle of the range.
// (raw pressure high --> OCR0A also high...)
/*
OCR0A += ((rawAirPressure - 1024) / rangewidth) - 1;
Delay_ms_Mess(1000);
 
pressureDiff = 0;
// DebugOut.Analog[16] = rawAirPressure;
 
#define PRESSURE_CAL_CYCLE_COUNT 5
for (i=0; i<PRESSURE_CAL_CYCLE_COUNT; i++) {
savedRawAirPressure = rawAirPressure;
OCR0A+=2;
Delay_ms_Mess(500);
// raw pressure will decrease.
pressureDiff += (savedRawAirPressure - rawAirPressure);
savedRawAirPressure = rawAirPressure;
OCR0A-=2;
Delay_ms_Mess(500);
// raw pressure will increase.
pressureDiff += (rawAirPressure - savedRawAirPressure);
}
 
rangewidth = (pressureDiff + PRESSURE_CAL_CYCLE_COUNT * 2 * 2 - 1) / (PRESSURE_CAL_CYCLE_COUNT * 2 * 2);
DebugOut.Analog[27] = rangewidth;
*/
}
/branches/dongfang_FC_rewrite/analog.h
24,66 → 24,66
// #define ACC_FILTER 4
 
/*
About setting constants for different gyros:
Main parameters are positive directions and voltage/angular speed gain.
The "Positive direction" is the rotation direction around an axis where
the corresponding gyro outputs a voltage > the no-rotation voltage.
A gyro is considered, in this code, to be "forward" if its positive
direction is:
- Nose down for pitch
- Left hand side down for roll
- Clockwise seen from above for yaw.
Declare the GYRO_REVERSE_YAW, GYRO_REVERSE_ROLL and
GYRO_REVERSE_PITCH #define's if the respective gyros are reverse.
About setting constants for different gyros:
Main parameters are positive directions and voltage/angular speed gain.
The "Positive direction" is the rotation direction around an axis where
the corresponding gyro outputs a voltage > the no-rotation voltage.
A gyro is considered, in this code, to be "forward" if its positive
direction is:
- Nose down for pitch
- Left hand side down for roll
- Clockwise seen from above for yaw.
Declare the GYRO_REVERSE_YAW, GYRO_REVERSE_ROLL and
GYRO_REVERSE_PITCH #define's if the respective gyros are reverse.
 
Setting gyro gain correctly: All sensor measurements in analog.c take
place in a cycle, each cycle comprising all sensors. Some sensors are
sampled more than ones, and the results added. The pitch and roll gyros
are sampled 4 times and the yaw gyro 2 times in the original H&I V0.74
code.
In the H&I code, the results for pitch and roll are multiplied by 2 (FC1.0)
or 4 (other versions), offset to zero, low pass filtered and then assigned
to the "HiResXXXX" and "AdWertXXXXFilter" variables, where XXXX is nick or
roll.
So:
 
gyro = V * (ADCValue1 + ADCValue2 + ADCValue3 + ADCValue4),
where V is 2 for FC1.0 and 4 for all others.
 
Assuming constant ADCValue, in the H&I code:
Setting gyro gain correctly: All sensor measurements in analog.c take
place in a cycle, each cycle comprising all sensors. Some sensors are
sampled more than ones, and the results added. The pitch and roll gyros
are sampled 4 times and the yaw gyro 2 times in the original H&I V0.74
code.
In the H&I code, the results for pitch and roll are multiplied by 2 (FC1.0)
or 4 (other versions), offset to zero, low pass filtered and then assigned
to the "HiResXXXX" and "AdWertXXXXFilter" variables, where XXXX is nick or
roll.
So:
gyro = V * (ADCValue1 + ADCValue2 + ADCValue3 + ADCValue4),
where V is 2 for FC1.0 and 4 for all others.
Assuming constant ADCValue, in the H&I code:
gyro = I * ADCValue.
gyro = I * ADCValue.
 
where I is 8 for FC1.0 and 16 for all others.
where I is 8 for FC1.0 and 16 for all others.
 
The relation between rotation rate and ADCValue:
ADCValue [units] =
rotational speed [deg/s] *
gyro sensitivity [V / deg/s] *
amplifier gain [units] *
1024 [units] /
3V full range [V]
The relation between rotation rate and ADCValue:
ADCValue [units] =
rotational speed [deg/s] *
gyro sensitivity [V / deg/s] *
amplifier gain [units] *
1024 [units] /
3V full range [V]
 
or: H is the number of steps the ADC value changes with,
for a 1 deg/s change in rotational velocity:
H = ADCValue [units] / rotation rate [deg/s] =
gyro sensitivity [V / deg/s] *
amplifier gain [units] *
1024 [units] /
3V full range [V]
or: H is the number of steps the ADC value changes with,
for a 1 deg/s change in rotational velocity:
H = ADCValue [units] / rotation rate [deg/s] =
gyro sensitivity [V / deg/s] *
amplifier gain [units] *
1024 [units] /
3V full range [V]
 
Examples:
FC1.3 has 0.67 mV/deg/s gyros and amplifiers with a gain of 5.7:
H = 0.00067 V / deg / s * 5.7 * 1024 / 3V = 1.304 units/(deg/s).
FC2.0 has 6*(3/5) mV/deg/s gyros (they are ratiometric) and no amplifiers:
H = 0.006 V / deg / s * 1 * 1024 * 3V / (3V * 5V) = 1.2288 units/(deg/s).
My InvenSense copter has 2mV/deg/s gyros and no amplifiers:
H = 0.002 V / deg / s * 1 * 1024 / 3V = 0.6827 units/(deg/s)
(only about half as sensitive as V1.3. But it will take about twice the
rotation rate!)
Examples:
FC1.3 has 0.67 mV/deg/s gyros and amplifiers with a gain of 5.7:
H = 0.00067 V / deg / s * 5.7 * 1024 / 3V = 1.304 units/(deg/s).
FC2.0 has 6*(3/5) mV/deg/s gyros (they are ratiometric) and no amplifiers:
H = 0.006 V / deg / s * 1 * 1024 * 3V / (3V * 5V) = 1.2288 units/(deg/s).
My InvenSense copter has 2mV/deg/s gyros and no amplifiers:
H = 0.002 V / deg / s * 1 * 1024 / 3V = 0.6827 units/(deg/s)
(only about half as sensitive as V1.3. But it will take about twice the
rotation rate!)
 
All together: gyro = I * H * rotation rate [units / (deg/s)].
*/
All together: gyro = I * H * rotation rate [units / (deg/s)].
*/
 
/*
* A factor that the raw gyro values are multiplied by,
108,38 → 108,38
#define ACC_SUMMATION_FACTOR_Z 1
 
/*
Integration:
The HiResXXXX values are divided by 8 (in H&I firmware) before integration.
In the Killagreg rewrite of the H&I firmware, the factor 8 is called
HIRES_GYRO_AMPLIFY. In this code, it is called HIRES_GYRO_INTEGRATION_FACTOR,
and care has been taken that all other constants (gyro to degree factor, and
180 degree flip-over detection limits) are corrected to it. Because the
division by the constant takes place in the flight attitude code, the
constant is there.
Integration:
The HiResXXXX values are divided by 8 (in H&I firmware) before integration.
In the Killagreg rewrite of the H&I firmware, the factor 8 is called
HIRES_GYRO_AMPLIFY. In this code, it is called HIRES_GYRO_INTEGRATION_FACTOR,
and care has been taken that all other constants (gyro to degree factor, and
180 degree flip-over detection limits) are corrected to it. Because the
division by the constant takes place in the flight attitude code, the
constant is there.
 
The control loop executes every 2ms, and for each iteration
gyro_ATT[PITCH/ROLL] is added to gyroIntegral[PITCH/ROLL].
Assuming a constant rotation rate v and a zero initial gyroIntegral
(for this explanation), we get:
gyroIntegral =
N * gyro / HIRES_GYRO_INTEGRATION_FACTOR =
N * I * H * v / HIRES_GYRO_INTEGRATION_FACTOR
where N is the number of summations; N = t/2ms.
The control loop executes every 2ms, and for each iteration
gyro_ATT[PITCH/ROLL] is added to gyroIntegral[PITCH/ROLL].
Assuming a constant rotation rate v and a zero initial gyroIntegral
(for this explanation), we get:
 
For one degree of rotation: t*v = 1:
gyroIntegral =
N * gyro / HIRES_GYRO_INTEGRATION_FACTOR =
N * I * H * v / HIRES_GYRO_INTEGRATION_FACTOR
 
gyroIntegralXXXX = t/2ms * I * H * 1/t = INTEGRATION_FREQUENCY * I * H / HIRES_GYRO_INTEGRATION_FACTOR.
where N is the number of summations; N = t/2ms.
 
This number (INTEGRATION_FREQUENCY * I * H) is the integral-to-degree factor.
For one degree of rotation: t*v = 1:
 
Examples:
FC1.3: I=2, H=1.304, HIRES_GYRO_INTEGRATION_FACTOR=8 --> integralDegreeFactor = 1304
FC2.0: I=2, H=2.048, HIRES_GYRO_INTEGRATION_FACTOR=13 --> integralDegreeFactor = 1260
My InvenSense copter: HIRES_GYRO_INTEGRATION_FACTOR=4, H=0.6827 --> integralDegreeFactor = 1365
*/
gyroIntegralXXXX = t/2ms * I * H * 1/t = INTEGRATION_FREQUENCY * I * H / HIRES_GYRO_INTEGRATION_FACTOR.
 
This number (INTEGRATION_FREQUENCY * I * H) is the integral-to-degree factor.
 
Examples:
FC1.3: I=2, H=1.304, HIRES_GYRO_INTEGRATION_FACTOR=8 --> integralDegreeFactor = 1304
FC2.0: I=2, H=2.048, HIRES_GYRO_INTEGRATION_FACTOR=13 --> integralDegreeFactor = 1260
My InvenSense copter: HIRES_GYRO_INTEGRATION_FACTOR=4, H=0.6827 --> integralDegreeFactor = 1365
*/
 
/*
* The value of gyro[PITCH/ROLL] for one deg/s = The hardware factor H * the number of samples * multiplier factor.
* Will be about 10 or so for InvenSense, and about 33 for ADXRS610.
239,7 → 239,6
*/
extern volatile uint8_t analogDataReady;
 
 
void analog_init(void);
 
// clear ADC enable & ADC Start Conversion & ADC Interrupt Enable bit
/branches/dongfang_FC_rewrite/attitude.c
239,9 → 239,8
ACRate[PITCH] = ((int32_t) rate_ATT[PITCH] * cosroll - (int32_t) yawRate
* sinroll) / (int32_t) MATH_UNIT_FACTOR;
ACRate[ROLL] = rate_ATT[ROLL] + (((int32_t) rate_ATT[PITCH] * sinroll
/ ANTIOVF * tanpitch + (int32_t) yawRate * int_cos(angle[ROLL])
/ ANTIOVF * tanpitch) / ((int32_t) MATH_UNIT_FACTOR / ANTIOVF
* MATH_UNIT_FACTOR));
/ ANTIOVF * tanpitch + (int32_t) yawRate * int_cos(angle[ROLL]) / ANTIOVF
* tanpitch) / ((int32_t) MATH_UNIT_FACTOR / ANTIOVF * MATH_UNIT_FACTOR));
ACYawRate = ((int32_t) rate_ATT[PITCH] * sinroll) / cospitch
+ ((int32_t) yawRate * cosroll) / cospitch;
}
327,8 → 326,7
*/
for (axis = PITCH; axis <= ROLL; axis++) {
accDerived = getAngleEstimateFromAcc(axis);
DebugOut.Analog[9 + axis] = (10 * accDerived)
/ GYRO_DEG_FACTOR_PITCHROLL;
DebugOut.Analog[9 + axis] = (10 * accDerived) / GYRO_DEG_FACTOR_PITCHROLL;
 
// 1000 * the correction amount that will be added to the gyro angle in next line.
correction = angle[axis]; //(permilleAcc * (accDerived - angle[axis])) / 1000;
370,16 → 368,14
timer = DRIFTCORRECTION_TIME;
for (axis = PITCH; axis <= ROLL; axis++) {
// Take the sum of corrections applied, add it to delta
deltaCorrection = (correctionSum[axis]
* HIRES_GYRO_INTEGRATION_FACTOR + DRIFTCORRECTION_TIME / 2)
/ DRIFTCORRECTION_TIME;
deltaCorrection = (correctionSum[axis] * HIRES_GYRO_INTEGRATION_FACTOR
+ DRIFTCORRECTION_TIME / 2) / DRIFTCORRECTION_TIME;
// Add the delta to the compensation. So positive delta means, gyro should have higher value.
driftComp[axis] += deltaCorrection / staticParams.GyroAccTrim;
CHECK_MIN_MAX(driftComp[axis], -staticParams.DriftComp, staticParams.DriftComp);
// DebugOut.Analog[11 + axis] = correctionSum[axis];
 
DebugOut.Analog[18 + axis] = deltaCorrection
/ staticParams.GyroAccTrim;
DebugOut.Analog[18 + axis] = deltaCorrection / staticParams.GyroAccTrim;
DebugOut.Analog[28 + axis] = driftComp[axis];
 
correctionSum[axis] = 0;
432,16 → 428,16
v = abs(angle[ROLL] / 512);
if (v > w)
w = v;
correction = w/8 + 1;
correction = w / 8 + 1;
// calculate the deviation of the yaw gyro heading and the compass heading
if (compassHeading < 0)
error = 0; // disable yaw drift compensation if compass heading is undefined
else
if (abs(yawRate) > 128) { // spinning fast
else if (abs(yawRate) > 128) { // spinning fast
error = 0;
} else {
// compassHeading - yawGyroHeading, on a -180..179 deg interval.
error = ((540 + compassHeading - (yawGyroHeading / GYRO_DEG_FACTOR_YAW)) % 360) - 180;
error = ((540 + compassHeading - (yawGyroHeading / GYRO_DEG_FACTOR_YAW))
% 360) - 180;
}
if (!ignoreCompassTimer && w < 25) {
yawGyroDrift += error;
456,10 → 452,11
yawGyroHeading += (error * 8) / correction;
 
/*
w = (w * dynamicParams.CompassYawEffect) / 32;
w = dynamicParams.CompassYawEffect - w;
*/
w = dynamicParams.CompassYawEffect - (w * dynamicParams.CompassYawEffect) / 32;
w = (w * dynamicParams.CompassYawEffect) / 32;
w = dynamicParams.CompassYawEffect - w;
*/
w = dynamicParams.CompassYawEffect - (w * dynamicParams.CompassYawEffect)
/ 32;
 
// As readable formula:
// w = dynamicParams.CompassYawEffect * (1-w/32);
468,7 → 465,9
if (!ignoreCompassTimer) {
v = 64 + (maxControl[PITCH] + maxControl[ROLL]) / 8;
// yawGyroHeading - compassCourse on a -180..179 degree interval.
r = ((540 + yawGyroHeading / GYRO_DEG_FACTOR_YAW - compassCourse) % 360) - 180;
r
= ((540 + yawGyroHeading / GYRO_DEG_FACTOR_YAW - compassCourse)
% 360) - 180;
v = (r * w) / v; // align to compass course
// limit yaw rate
w = 3 * dynamicParams.CompassYawEffect;
/branches/dongfang_FC_rewrite/attitudeControl.c
8,39 → 8,40
#include "rc.h"
 
// = cos^2(45 degs).
const int32_t MINPROJECTION = (int32_t)MATH_UNIT_FACTOR * MATH_UNIT_FACTOR / 2;
const int32_t MINPROJECTION = (int32_t) MATH_UNIT_FACTOR * MATH_UNIT_FACTOR / 2;
 
// Takes 380 - 400 usec. Way too slow.
// With static MINPROJECTION: 220 usec.
uint16_t AC_getThrottle(uint16_t throttle) {
int32_t projection;
int32_t projection;
 
// part1 start: 150 usec
// It's factor (int32_t)MATH_UNIT_FACTOR^2 too high.
projection = (int32_t)int_cos(angle[PITCH]) * (int32_t)int_cos(angle[ROLL]);
// part1 end.
// part1 start: 150 usec
// It's factor (int32_t)MATH_UNIT_FACTOR^2 too high.
projection = (int32_t) int_cos(angle[PITCH]) * (int32_t) int_cos(angle[ROLL]);
// part1 end.
 
uint8_t effect = dynamicParams.UserParams[2]; // Userparam 3
int16_t deltaThrottle;
uint8_t effect = dynamicParams.UserParams[2]; // Userparam 3
int16_t deltaThrottle;
 
if (projection < MINPROJECTION && projection >= 0) {
// projection = MINPROJECTION;
deltaThrottle = 0;
} else if (projection >- MINPROJECTION && projection<0) {
// projection = -MINPROJECITON;
deltaThrottle = 0;
} else
/*
* We need delta throttle = constant/projection1
* (constant * MATH_UNIT_FACTOR^2) / projection.
*/
deltaThrottle = ((int32_t)effect * (int32_t)MATH_UNIT_FACTOR * (int32_t)MATH_UNIT_FACTOR) / (projection / 10) - effect * 10;
// DebugOut.Analog[13] = deltaThrottle;
if (projection < MINPROJECTION && projection >= 0) {
// projection = MINPROJECTION;
deltaThrottle = 0;
} else if (projection > -MINPROJECTION && projection < 0) {
// projection = -MINPROJECITON;
deltaThrottle = 0;
} else
/*
* We need delta throttle = constant/projection1
* (constant * MATH_UNIT_FACTOR^2) / projection.
*/
deltaThrottle = ((int32_t) effect * (int32_t) MATH_UNIT_FACTOR
* (int32_t) MATH_UNIT_FACTOR) / (projection / 10) - effect * 10;
// DebugOut.Analog[13] = deltaThrottle;
 
return throttle + deltaThrottle;
return throttle + deltaThrottle;
}
/*
har: R = e * k/p
vil R = e * ( 1 - k/p )
= e - ek/p
*/
har: R = e * k/p
vil R = e * ( 1 - k/p )
= e - ek/p
*/
/branches/dongfang_FC_rewrite/commands.c
57,69 → 57,70
#include "attitude.h"
 
void commands_handleCommands(void) {
/*
* Get the current command (start/stop motors, calibrate), if any.
*/
uint8_t command = controlMixer_getCommand();
uint8_t repeated = controlMixer_isCommandRepeated();
uint8_t argument = controlMixer_getArgument();
/*
* Get the current command (start/stop motors, calibrate), if any.
*/
uint8_t command = controlMixer_getCommand();
uint8_t repeated = controlMixer_isCommandRepeated();
uint8_t argument = controlMixer_getArgument();
 
if(!(MKFlags & MKFLAG_MOTOR_RUN)) {
if (command == COMMAND_GYROCAL && !repeated) {
// Run gyro calibration but do not repeat it.
GRN_OFF;
// TODO: out of here. Anyway, MKFLAG_MOTOR_RUN is cleared. Not enough?
// isFlying = 0;
// check roll/pitch stick position
// if pitch stick is top or roll stick is left or right --> change parameter setting
// according to roll/pitch stick position
if (!(MKFlags & MKFLAG_MOTOR_RUN)) {
if (command == COMMAND_GYROCAL && !repeated) {
// Run gyro calibration but do not repeat it.
GRN_OFF;
 
if (argument < 6) {
// Gyro calinbration, with or without selecting a new parameter-set.
if(argument > 0 && argument < 6) {
// A valid parameter-set (1..5) was chosen - use it.
setActiveParamSet(argument);
}
ParamSet_ReadFromEEProm(getActiveParamSet());
attitude_setNeutral();
flight_setNeutral();
controlMixer_setNeutral();
beepNumber(getActiveParamSet());
} else if(staticParams.GlobalConfig & (CFG_COMPASS_ACTIVE | CFG_GPS_ACTIVE) && argument == 7) {
// If right stick is centered and down
// TODO: Out of here! State machine instead.
compassCalState = 1;
beep(1000);
// TODO: out of here. Anyway, MKFLAG_MOTOR_RUN is cleared. Not enough?
// isFlying = 0;
// check roll/pitch stick position
// if pitch stick is top or roll stick is left or right --> change parameter setting
// according to roll/pitch stick position
 
if (argument < 6) {
// Gyro calinbration, with or without selecting a new parameter-set.
if (argument > 0 && argument < 6) {
// A valid parameter-set (1..5) was chosen - use it.
setActiveParamSet(argument);
}
ParamSet_ReadFromEEProm(getActiveParamSet());
attitude_setNeutral();
flight_setNeutral();
controlMixer_setNeutral();
beepNumber(getActiveParamSet());
} else if (staticParams.GlobalConfig & (CFG_COMPASS_ACTIVE
| CFG_GPS_ACTIVE) && argument == 7) {
// If right stick is centered and down
// TODO: Out of here! State machine instead.
compassCalState = 1;
beep(1000);
}
}
 
// save the ACC neutral setting to eeprom
else {
if (command == COMMAND_ACCCAL && !repeated) {
// Run gyro and acc. meter calibration but do not repeat it.
GRN_OFF;
analog_calibrateAcc();
attitude_setNeutral();
flight_setNeutral();
controlMixer_setNeutral();
beepNumber(getActiveParamSet());
}
}
} // end !MOTOR_RUN condition.
if (command == COMMAND_START) {
isFlying = 1; // TODO: Really????
// if (!controlMixer_isCommandRepeated()) {
// attitude_startDynamicCalibration(); // Try sense the effect of the motors on sensors.
MKFlags |= (MKFLAG_MOTOR_RUN | MKFLAG_START); // set flag RUN and START. TODO: Is that START flag used at all???
// } else { // Pilot is holding stick, ever after motor start. Continue to sense the effect of the motors on sensors.
// attitude_continueDynamicCalibration();
// setPointYaw = 0;
// IPartPitch = 0;
// IPartRoll = 0;
// }
} else if (command == COMMAND_STOP) {
isFlying = 0;
MKFlags &= ~(MKFLAG_MOTOR_RUN);
}
}
 
// save the ACC neutral setting to eeprom
else {
if(command == COMMAND_ACCCAL && !repeated) {
// Run gyro and acc. meter calibration but do not repeat it.
GRN_OFF;
analog_calibrateAcc();
attitude_setNeutral();
flight_setNeutral();
controlMixer_setNeutral();
beepNumber(getActiveParamSet());
}
}
} // end !MOTOR_RUN condition.
if (command == COMMAND_START) {
isFlying = 1; // TODO: Really????
// if (!controlMixer_isCommandRepeated()) {
// attitude_startDynamicCalibration(); // Try sense the effect of the motors on sensors.
MKFlags |= (MKFLAG_MOTOR_RUN | MKFLAG_START); // set flag RUN and START. TODO: Is that START flag used at all???
// } else { // Pilot is holding stick, ever after motor start. Continue to sense the effect of the motors on sensors.
// attitude_continueDynamicCalibration();
// setPointYaw = 0;
// IPartPitch = 0;
// IPartRoll = 0;
// }
} else if (command == COMMAND_STOP) {
isFlying = 0;
MKFlags &= ~(MKFLAG_MOTOR_RUN);
}
}
/branches/dongfang_FC_rewrite/configuration.h
5,129 → 5,129
#include <avr/io.h>
 
typedef struct {
/*PMM*/ uint8_t HeightD;
/* P */ uint8_t MaxHeight;
/*PMM*/ uint8_t HeightP;
/* P */ uint8_t Height_ACC_Effect;
/* P */ uint8_t CompassYawEffect;
/* P */ uint8_t GyroD;
/*PMM*/ uint8_t GyroP;
/* P */ uint8_t GyroI;
/* Never used */ uint8_t StickYawP;
/* P */ uint8_t IFactor;
/* P */ uint8_t UserParams[8];
/* P */ uint8_t ServoPitchControl;
/* P */ uint8_t LoopGasLimit;
/* P */ uint8_t AxisCoupling1;
/* P */ uint8_t AxisCoupling2;
/* P */ uint8_t AxisCouplingYawCorrection;
/* P */ uint8_t DynamicStability;
/* P */ uint8_t ExternalControl;
/*PMM*/ uint8_t J16Timing;
/*PMM*/ uint8_t J17Timing;
/* P */ uint8_t NaviGpsModeControl;
/* P */ uint8_t NaviGpsGain;
/* P */ uint8_t NaviGpsP;
/* P */ uint8_t NaviGpsI;
/* P */ uint8_t NaviGpsD;
/* P */ uint8_t NaviGpsACC;
/*PMM*/ uint8_t NaviOperatingRadius;
/* P */ uint8_t NaviWindCorrection;
/* P */ uint8_t NaviSpeedCompensation;
int8_t KalmanK;
int8_t KalmanMaxDrift;
int8_t KalmanMaxFusion;
/*PMM*/uint8_t HeightD;
/* P */uint8_t MaxHeight;
/*PMM*/uint8_t HeightP;
/* P */uint8_t Height_ACC_Effect;
/* P */uint8_t CompassYawEffect;
/* P */uint8_t GyroD;
/*PMM*/uint8_t GyroP;
/* P */uint8_t GyroI;
/* Never used */uint8_t StickYawP;
/* P */uint8_t IFactor;
/* P */uint8_t UserParams[8];
/* P */uint8_t ServoPitchControl;
/* P */uint8_t LoopGasLimit;
/* P */uint8_t AxisCoupling1;
/* P */uint8_t AxisCoupling2;
/* P */uint8_t AxisCouplingYawCorrection;
/* P */uint8_t DynamicStability;
/* P */uint8_t ExternalControl;
/*PMM*/uint8_t J16Timing;
/*PMM*/uint8_t J17Timing;
/* P */uint8_t NaviGpsModeControl;
/* P */uint8_t NaviGpsGain;
/* P */uint8_t NaviGpsP;
/* P */uint8_t NaviGpsI;
/* P */uint8_t NaviGpsD;
/* P */uint8_t NaviGpsACC;
/*PMM*/uint8_t NaviOperatingRadius;
/* P */uint8_t NaviWindCorrection;
/* P */uint8_t NaviSpeedCompensation;
int8_t KalmanK;
int8_t KalmanMaxDrift;
int8_t KalmanMaxFusion;
} dynamicParam_t;
extern dynamicParam_t dynamicParams;
 
typedef struct {
uint8_t sourceIdx, targetIdx;
uint8_t min, max;
uint8_t sourceIdx, targetIdx;
uint8_t min, max;
} MMXLATION;
 
typedef struct {
uint8_t sourceIdx, targetIdx;
uint8_t sourceIdx, targetIdx;
} XLATION;
 
// values above 250 representing poti1 to poti4
typedef struct {
uint8_t ChannelAssignment[8]; // see upper defines for details
uint8_t GlobalConfig; // see upper defines for bitcoding
uint8_t HeightMinGas; // Value : 0-100
uint8_t HeightD; // Value : 0-250
uint8_t MaxHeight; // Value : 0-32
uint8_t HeightP; // Value : 0-32
uint8_t Height_Gain; // Value : 0-50
uint8_t Height_ACC_Effect; // Value : 0-250
uint8_t StickP; // Value : 1-6
uint8_t StickD; // Value : 0-64
uint8_t StickYawP; // Value : 1-20
uint8_t MinThrottle; // Value : 0-32
uint8_t MaxThrottle; // Value : 33-250
uint8_t GyroAccFactor; // Value : 1-64
uint8_t CompassYawEffect; // Value : 0-32
uint8_t GyroP; // Value : 10-250
uint8_t GyroI; // Value : 0-250
uint8_t GyroD; // Value : 0-250
uint8_t LowVoltageWarning; // Value : 0-250
uint8_t EmergencyGas; // Value : 0-250 //Gaswert bei Emp�ngsverlust
uint8_t EmergencyGasDuration; // Value : 0-250 // Zeitbis auf EmergencyGas geschaltet wird, wg. Rx-Problemen
uint8_t Unused0; //
uint8_t IFactor; // Value : 0-250
uint8_t UserParams1[4]; // Value : 0-250
/*
uint8_t UserParam2; // Value : 0-250
uint8_t UserParam3; // Value : 0-250
uint8_t UserParam4; // Value : 0-250
*/
uint8_t ServoPitchControl; // Value : 0-250 // Stellung des Servos
uint8_t ServoPitchComp; // Value : 0-250 // Einfluss Gyro/Servo
uint8_t ServoPitchMin; // Value : 0-250 // Anschlag
uint8_t ServoPitchMax; // Value : 0-250 // Anschlag
uint8_t ServoRefresh; // Value: 0-250 // Refreshrate of servo pwm output
uint8_t LoopGasLimit; // Value: 0-250 max. Gas w�hrend Looping
uint8_t LoopThreshold; // Value: 0-250 Schwelle f�r Stickausschlag
uint8_t LoopHysteresis; // Value: 0-250 Hysterese f�r Stickausschlag
uint8_t AxisCoupling1; // Value: 0-250 Faktor, mit dem Yaw die Achsen Roll und Nick koppelt (NickRollMitkopplung)
uint8_t AxisCoupling2; // Value: 0-250 Faktor, mit dem Nick und Roll verkoppelt werden
uint8_t ChannelAssignment[8]; // see upper defines for details
uint8_t GlobalConfig; // see upper defines for bitcoding
uint8_t HeightMinGas; // Value : 0-100
uint8_t HeightD; // Value : 0-250
uint8_t MaxHeight; // Value : 0-32
uint8_t HeightP; // Value : 0-32
uint8_t Height_Gain; // Value : 0-50
uint8_t Height_ACC_Effect; // Value : 0-250
uint8_t StickP; // Value : 1-6
uint8_t StickD; // Value : 0-64
uint8_t StickYawP; // Value : 1-20
uint8_t MinThrottle; // Value : 0-32
uint8_t MaxThrottle; // Value : 33-250
uint8_t GyroAccFactor; // Value : 1-64
uint8_t CompassYawEffect; // Value : 0-32
uint8_t GyroP; // Value : 10-250
uint8_t GyroI; // Value : 0-250
uint8_t GyroD; // Value : 0-250
uint8_t LowVoltageWarning; // Value : 0-250
uint8_t EmergencyGas; // Value : 0-250 //Gaswert bei Emp�ngsverlust
uint8_t EmergencyGasDuration; // Value : 0-250 // Zeitbis auf EmergencyGas geschaltet wird, wg. Rx-Problemen
uint8_t Unused0; //
uint8_t IFactor; // Value : 0-250
uint8_t UserParams1[4]; // Value : 0-250
/*
uint8_t UserParam2; // Value : 0-250
uint8_t UserParam3; // Value : 0-250
uint8_t UserParam4; // Value : 0-250
*/
uint8_t ServoPitchControl; // Value : 0-250 // Stellung des Servos
uint8_t ServoPitchComp; // Value : 0-250 // Einfluss Gyro/Servo
uint8_t ServoPitchMin; // Value : 0-250 // Anschlag
uint8_t ServoPitchMax; // Value : 0-250 // Anschlag
uint8_t ServoRefresh; // Value: 0-250 // Refreshrate of servo pwm output
uint8_t LoopGasLimit; // Value: 0-250 max. Gas w�hrend Looping
uint8_t LoopThreshold; // Value: 0-250 Schwelle f�r Stickausschlag
uint8_t LoopHysteresis; // Value: 0-250 Hysterese f�r Stickausschlag
uint8_t AxisCoupling1; // Value: 0-250 Faktor, mit dem Yaw die Achsen Roll und Nick koppelt (NickRollMitkopplung)
uint8_t AxisCoupling2; // Value: 0-250 Faktor, mit dem Nick und Roll verkoppelt werden
uint8_t AxisCouplingYawCorrection;// Value: 0-250 Faktor, mit dem Nick und Roll verkoppelt werden
uint8_t AngleTurnOverPitch; // Value: 0-250 180�-Punkt
uint8_t AngleTurnOverRoll; // Value: 0-250 180�-Punkt
uint8_t GyroAccTrim; // 1/k (Koppel_ACC_Wirkung)
uint8_t DriftComp; // limit for gyrodrift compensation
uint8_t DynamicStability; // PID limit for Attitude controller
uint8_t UserParams2[4]; // Value : 0-250
/*
uint8_t UserParam6; // Value : 0-250
uint8_t UserParam7; // Value : 0-250
uint8_t UserParam8; // Value : 0-250
*/
uint8_t J16Bitmask; // for the J16 Output
uint8_t J16Timing; // for the J16 Output
uint8_t J17Bitmask; // for the J17 Output
uint8_t J17Timing; // for the J17 Output
uint8_t NaviGpsModeControl; // Parameters for the Naviboard
uint8_t NaviGpsGain; // overall gain for GPS-PID controller
uint8_t NaviGpsP; // P gain for GPS-PID controller
uint8_t NaviGpsI; // I gain for GPS-PID controller
uint8_t NaviGpsD; // D gain for GPS-PID controller
uint8_t NaviGpsPLimit; // P limit for GPS-PID controller
uint8_t NaviGpsILimit; // I limit for GPS-PID controller
uint8_t NaviGpsDLimit; // D limit for GPS-PID controller
uint8_t NaviGpsACC; // ACC gain for GPS-PID controller
uint8_t NaviGpsMinSat; // number of sattelites neccesary for GPS functions
uint8_t NaviStickThreshold; // activation threshild for detection of manual stick movements
uint8_t NaviWindCorrection; // streng of wind course correction
uint8_t NaviSpeedCompensation; // D gain fefore position hold login
uint8_t NaviOperatingRadius; // Radius limit in m around start position for GPS flights
uint8_t NaviAngleLimitation; // limitation of attitude angle controlled by the gps algorithm
uint8_t NaviPHLoginTime; // position hold logintimeout
uint8_t ExternalControl; // for serial Control
uint8_t BitConfig; // see upper defines for bitcoding
uint8_t ServoPitchCompInvert; // Value : 0-250 0 oder 1 // WICHTIG!!! am Ende lassen
uint8_t AngleTurnOverPitch; // Value: 0-250 180�-Punkt
uint8_t AngleTurnOverRoll; // Value: 0-250 180�-Punkt
uint8_t GyroAccTrim; // 1/k (Koppel_ACC_Wirkung)
uint8_t DriftComp; // limit for gyrodrift compensation
uint8_t DynamicStability; // PID limit for Attitude controller
uint8_t UserParams2[4]; // Value : 0-250
/*
uint8_t UserParam6; // Value : 0-250
uint8_t UserParam7; // Value : 0-250
uint8_t UserParam8; // Value : 0-250
*/
uint8_t J16Bitmask; // for the J16 Output
uint8_t J16Timing; // for the J16 Output
uint8_t J17Bitmask; // for the J17 Output
uint8_t J17Timing; // for the J17 Output
uint8_t NaviGpsModeControl; // Parameters for the Naviboard
uint8_t NaviGpsGain; // overall gain for GPS-PID controller
uint8_t NaviGpsP; // P gain for GPS-PID controller
uint8_t NaviGpsI; // I gain for GPS-PID controller
uint8_t NaviGpsD; // D gain for GPS-PID controller
uint8_t NaviGpsPLimit; // P limit for GPS-PID controller
uint8_t NaviGpsILimit; // I limit for GPS-PID controller
uint8_t NaviGpsDLimit; // D limit for GPS-PID controller
uint8_t NaviGpsACC; // ACC gain for GPS-PID controller
uint8_t NaviGpsMinSat; // number of sattelites neccesary for GPS functions
uint8_t NaviStickThreshold; // activation threshild for detection of manual stick movements
uint8_t NaviWindCorrection; // streng of wind course correction
uint8_t NaviSpeedCompensation; // D gain fefore position hold login
uint8_t NaviOperatingRadius; // Radius limit in m around start position for GPS flights
uint8_t NaviAngleLimitation; // limitation of attitude angle controlled by the gps algorithm
uint8_t NaviPHLoginTime; // position hold logintimeout
uint8_t ExternalControl; // for serial Control
uint8_t BitConfig; // see upper defines for bitcoding
uint8_t ServoPitchCompInvert; // Value : 0-250 0 oder 1 // WICHTIG!!! am Ende lassen
uint8_t Reserved[4];
int8_t Name[12];
} paramset_t;
} paramset_t;
 
#define PARAMSET_STRUCT_LEN sizeof(paramset_t)
 
134,10 → 134,10
extern paramset_t staticParams;
 
typedef struct {
uint8_t Revision;
int8_t Name[12];
int8_t Motor[16][4];
} __attribute__((packed)) MixerTable_t;
uint8_t Revision;
int8_t Name[12];
int8_t Motor[16][4];
}__attribute__((packed)) MixerTable_t;
 
extern MixerTable_t Mixer;
 
/branches/dongfang_FC_rewrite/controlMixer.c
60,13 → 60,13
#include "commands.h"
#include "output.h"
 
uint16_t maxControl[2] = {0,0};
int16_t control[2] = {0,0};
uint16_t maxControl[2] = { 0, 0 };
int16_t control[2] = { 0, 0 };
int16_t controlYaw = 0, controlThrottle = 0;
uint8_t looping = 0;
 
// Internal variables for reading commands made with an R/C stick.
uint8_t lastCommand = COMMAND_NONE;
uint8_t lastCommand = COMMAND_NONE;
uint8_t lastArgument;
 
uint8_t isCommandRepeated = 0;
80,7 → 80,7
* (read: Custom MK RC project)
*/
uint8_t controlMixer_getArgument(void) {
return lastArgument;
return lastArgument;
}
 
/*
88,16 → 88,16
* than the R/C (read: Custom MK R/C project)
*/
uint8_t controlMixer_getCommand(void) {
return lastCommand;
return lastCommand;
}
 
uint8_t controlMixer_isCommandRepeated(void) {
return isCommandRepeated;
return isCommandRepeated;
}
 
void controlMixer_setNeutral() {
EC_setNeutral();
HC_setGround();
EC_setNeutral();
HC_setGround();
}
 
/*
105,10 → 105,10
* No slew rate limitation.
*/
void controlMixer_initVariables(void) {
uint8_t i;
for (i=0; i<8; i++) {
variables[i] = RC_getVariable(i);
}
uint8_t i;
for (i = 0; i < 8; i++) {
variables[i] = RC_getVariable(i);
}
}
 
/*
116,20 → 116,24
* TODO: It assumes R/C as source. Not necessarily true.
*/
void controlMixer_updateVariables(void) {
uint8_t i;
int16_t targetvalue;
for (i=0; i<8; i++) {
targetvalue = RC_getVariable(i);
if (targetvalue < 0) targetvalue = 0;
if (variables[i] < targetvalue && variables[i] < 255) variables[i]++; else if(variables[i] > 0 && variables[i] > targetvalue) variables[i]--;
}
uint8_t i;
int16_t targetvalue;
for (i = 0; i < 8; i++) {
targetvalue = RC_getVariable(i);
if (targetvalue < 0)
targetvalue = 0;
if (variables[i] < targetvalue && variables[i] < 255)
variables[i]++;
else if (variables[i] > 0 && variables[i] > targetvalue)
variables[i]--;
}
}
 
uint8_t controlMixer_getSignalQuality(void) {
uint8_t rcQ = RC_getSignalQuality();
uint8_t ecQ = EC_getSignalQuality();
// This needs not be the only correct solution...
return rcQ > ecQ ? rcQ : ecQ;
uint8_t rcQ = RC_getSignalQuality();
uint8_t ecQ = EC_getSignalQuality();
// This needs not be the only correct solution...
return rcQ > ecQ ? rcQ : ecQ;
}
 
/*
136,87 → 140,98
* Update the variables indicating stick position from the sum of R/C, GPS and external control.
*/
void controlMixer_update(void) {
// calculate Stick inputs by rc channels (P) and changing of rc channels (D)
// TODO: If no signal --> zero.
uint8_t axis;
// calculate Stick inputs by rc channels (P) and changing of rc channels (D)
// TODO: If no signal --> zero.
uint8_t axis;
 
// takes almost no time...
RC_update();
// takes almost no time...
EC_update();
// takes almost no time...
RC_update();
 
// takes about 80 usec.
HC_update();
// takes almost no time...
EC_update();
 
int16_t* RC_PRTY = RC_getPRTY();
int16_t* EC_PRTY = EC_getPRTY();
// takes about 80 usec.
HC_update();
 
control[PITCH] = RC_PRTY[CONTROL_PITCH] + EC_PRTY[CONTROL_PITCH];
control[ROLL] = RC_PRTY[CONTROL_ROLL] + EC_PRTY[CONTROL_ROLL];
// This can be a CPU time killer if the function implementations are inefficient.
controlThrottle = HC_getThrottle(AC_getThrottle(RC_PRTY[CONTROL_THROTTLE] + EC_PRTY[CONTROL_THROTTLE]));
controlYaw = RC_PRTY[CONTROL_YAW] + EC_PRTY[CONTROL_YAW];
int16_t* RC_PRTY = RC_getPRTY();
int16_t* EC_PRTY = EC_getPRTY();
 
DebugOut.Analog[12] = control[PITCH];
DebugOut.Analog[13] = control[ROLL];
//DebugOut.Analog[26] = controlYaw;
control[PITCH] = RC_PRTY[CONTROL_PITCH] + EC_PRTY[CONTROL_PITCH];
control[ROLL] = RC_PRTY[CONTROL_ROLL] + EC_PRTY[CONTROL_ROLL];
// This can be a CPU time killer if the function implementations are inefficient.
controlThrottle = HC_getThrottle(AC_getThrottle(RC_PRTY[CONTROL_THROTTLE]
+ EC_PRTY[CONTROL_THROTTLE]));
controlYaw = RC_PRTY[CONTROL_YAW] + EC_PRTY[CONTROL_YAW];
 
if (controlMixer_getSignalQuality() >= SIGNAL_GOOD) {
controlMixer_updateVariables();
configuration_applyVariablesToParams();
looping = RC_getLooping(looping);
} else { // Signal is not OK
// Could handle switch to emergency flight here.
// throttle is handled elsewhere.
looping = 0;
}
DebugOut.Analog[12] = control[PITCH];
DebugOut.Analog[13] = control[ROLL];
//DebugOut.Analog[26] = controlYaw;
 
// part1a end.
if (controlMixer_getSignalQuality() >= SIGNAL_GOOD) {
controlMixer_updateVariables();
configuration_applyVariablesToParams();
looping = RC_getLooping(looping);
} else { // Signal is not OK
// Could handle switch to emergency flight here.
// throttle is handled elsewhere.
looping = 0;
}
 
/* This is not really necessary with the dead-gap feature on all sticks (see rc.c)
if(staticParams.GlobalConfig & (CFG_COMPASS_ACTIVE | CFG_GPS_ACTIVE)) {
if (controlYaw > 2) controlYaw-= 2;
else if (controlYaw< -2) controlYaw += 2;
else controlYaw = 0;
}
*/
// part1a end.
 
/*
* Record maxima
*/
for (axis=PITCH; axis<=ROLL; axis++) {
if(abs(control[axis] / CONTROL_SCALING) > maxControl[axis]) {
maxControl[axis] = abs(control[axis]) / CONTROL_SCALING;
if(maxControl[axis] > 100) maxControl[axis] = 100;
} else if (maxControl[axis]) maxControl[axis]--;
}
/* This is not really necessary with the dead-gap feature on all sticks (see rc.c)
if(staticParams.GlobalConfig & (CFG_COMPASS_ACTIVE | CFG_GPS_ACTIVE)) {
if (controlYaw > 2) controlYaw-= 2;
else if (controlYaw< -2) controlYaw += 2;
else controlYaw = 0;
}
*/
 
uint8_t rcCommand = (RC_getSignalQuality() >= SIGNAL_OK) ? RC_getCommand() : COMMAND_NONE;
uint8_t ecCommand = (EC_getSignalQuality() >= SIGNAL_OK) ? EC_getCommand() : COMMAND_NONE;
if (rcCommand != COMMAND_NONE) {
isCommandRepeated = (lastCommand == rcCommand);
lastCommand = rcCommand;
lastArgument = RC_getArgument();
} else if (ecCommand != COMMAND_NONE) {
isCommandRepeated = (lastCommand == ecCommand);
lastCommand = ecCommand;
lastArgument = EC_getArgument();
} else {
// Both sources have no command, or one or both are out.
// Just set to false. There is no reason to check if the none-command was repeated anyway.
isCommandRepeated = 0;
lastCommand = COMMAND_NONE;
}
/*
* Record maxima
*/
for (axis = PITCH; axis <= ROLL; axis++) {
if (abs(control[axis] / CONTROL_SCALING) > maxControl[axis]) {
maxControl[axis] = abs(control[axis]) / CONTROL_SCALING;
if (maxControl[axis] > 100)
maxControl[axis] = 100;
} else if (maxControl[axis])
maxControl[axis]--;
}
 
if (isCommandRepeated) DebugOut.Digital[0] |= DEBUG_COMMANDREPEATED; else DebugOut.Digital[0] &= ~DEBUG_COMMANDREPEATED;
if (rcCommand) DebugOut.Digital[1] |= DEBUG_COMMANDREPEATED; else DebugOut.Digital[1] &= ~DEBUG_COMMANDREPEATED;
uint8_t rcCommand = (RC_getSignalQuality() >= SIGNAL_OK) ? RC_getCommand()
: COMMAND_NONE;
uint8_t ecCommand = (EC_getSignalQuality() >= SIGNAL_OK) ? EC_getCommand()
: COMMAND_NONE;
 
// part1 end.
if (rcCommand != COMMAND_NONE) {
isCommandRepeated = (lastCommand == rcCommand);
lastCommand = rcCommand;
lastArgument = RC_getArgument();
} else if (ecCommand != COMMAND_NONE) {
isCommandRepeated = (lastCommand == ecCommand);
lastCommand = ecCommand;
lastArgument = EC_getArgument();
} else {
// Both sources have no command, or one or both are out.
// Just set to false. There is no reason to check if the none-command was repeated anyway.
isCommandRepeated = 0;
lastCommand = COMMAND_NONE;
}
 
if (isCommandRepeated)
DebugOut.Digital[0] |= DEBUG_COMMANDREPEATED;
else
DebugOut.Digital[0] &= ~DEBUG_COMMANDREPEATED;
if (rcCommand)
DebugOut.Digital[1] |= DEBUG_COMMANDREPEATED;
else
DebugOut.Digital[1] &= ~DEBUG_COMMANDREPEATED;
 
// part1 end.
}
 
// TODO: Integrate into command system.
uint8_t controlMixer_testCompassCalState(void) {
return RC_testCompassCalState();
return RC_testCompassCalState();
}
/branches/dongfang_FC_rewrite/controlMixer.h
7,7 → 7,7
* each other, the priorities between them and the behavior in case that one fails is simplified,
* and all in one place.
*/
 
/*
* Signal qualities, used to determine the availability of a control.
* NO_SIGNAL means there was never a signal. SIGNAL_LOST that there was a signal, but it was lost.
47,25 → 47,25
* same interface. This struct of code pointers is used like an abstract class
* definition from object-oriented languages, and all control input implementations
* will declare an instance of the stuct (=implementation of the abstract class).
*/
*/
typedef struct {
/* Get the pitch input in the nominal range [-STICK_RANGE, STICK_RANGE]. */
int16_t(*getPitch)(void);
/* Get the pitch input in the nominal range [-STICK_RANGE, STICK_RANGE]. */
int16_t(*getPitch)(void);
 
/* Get the roll input in the nominal range [-STICK_RANGE, STICK_RANGE]. */
int16_t(*getRoll)(void);
/* Get the yaw input in the nominal range [-STICK_RANGE, STICK_RANGE]. */
int16_t(*getYaw)(void);
/* Get the throttle input in the nominal range [0, THROTTLE_RANGE]. */
uint16_t(*getThrottle)(void);
int16_t(*getRoll)(void);
 
/* Signal quality, by the above SIGNAL_... definitions. */
uint8_t (*getSignalQuality)(void);
/* Get the yaw input in the nominal range [-STICK_RANGE, STICK_RANGE]. */
int16_t(*getYaw)(void);
 
/* Calibrate sticks to their center positions (only relevant for R/C, really) */
void (*calibrate)(void);
/* Get the throttle input in the nominal range [0, THROTTLE_RANGE]. */
uint16_t(*getThrottle)(void);
 
/* Signal quality, by the above SIGNAL_... definitions. */
uint8_t (*getSignalQuality)(void);
 
/* Calibrate sticks to their center positions (only relevant for R/C, really) */
void (*calibrate)(void);
} t_control;
 
/*
/branches/dongfang_FC_rewrite/dongfangMath.c
2,230 → 2,228
#include <inttypes.h>
#include <avr/pgmspace.h>
 
const int16_t SIN_TABLE[] PROGMEM = {
(int16_t) (0.0 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.01745240643728351 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.03489949670250097 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.05233595624294383 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.0697564737441253 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.08715574274765817 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.10452846326765346 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.12186934340514748 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.13917310096006544 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.15643446504023087 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.17364817766693033 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.1908089953765448 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.20791169081775931 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.224951054343865 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.24192189559966773 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.25881904510252074 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.27563735581699916 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.29237170472273677 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.3090169943749474 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.32556815445715664 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.3420201433256687 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.35836794954530027 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.374606593415912 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.3907311284892737 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.40673664307580015 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.42261826174069944 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.4383711467890774 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.45399049973954675 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.4694715627858908 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.48480962024633706 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.49999999999999994 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5150380749100542 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5299192642332049 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5446390350150271 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5591929034707469 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.573576436351046 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5877852522924731 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6018150231520483 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6156614753256582 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6293203910498374 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6427876096865393 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6560590289905072 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6691306063588582 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6819983600624985 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6946583704589973 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7071067811865475 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7193398003386511 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7313537016191705 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7431448254773942 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.754709580222772 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.766044443118978 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7771459614569708 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.788010753606722 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7986355100472928 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8090169943749475 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8191520442889918 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8290375725550417 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8386705679454239 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8480480961564261 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8571673007021122 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8660254037844386 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8746197071393957 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8829475928589269 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8910065241883678 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.898794046299167 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9063077870366499 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9135454576426009 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9205048534524403 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9271838545667874 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9335804264972017 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9396926207859083 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9455185755993167 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9510565162951535 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9563047559630354 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9612616959383189 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9659258262890683 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9702957262759965 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9743700647852352 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9781476007338056 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.981627183447664 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.984807753012208 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9876883405951378 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9902680687415703 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.992546151641322 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9945218953682733 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9961946980917455 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9975640502598242 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9986295347545738 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9993908270190958 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9998476951563913 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.0 * MATH_UNIT_FACTOR) };
const int16_t SIN_TABLE[] PROGMEM = { (int16_t) (0.0 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.01745240643728351 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.03489949670250097 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.05233595624294383 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.0697564737441253 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.08715574274765817 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.10452846326765346 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.12186934340514748 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.13917310096006544 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.15643446504023087 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.17364817766693033 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.1908089953765448 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.20791169081775931 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.224951054343865 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.24192189559966773 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.25881904510252074 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.27563735581699916 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.29237170472273677 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.3090169943749474 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.32556815445715664 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.3420201433256687 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.35836794954530027 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.374606593415912 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.3907311284892737 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.40673664307580015 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.42261826174069944 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.4383711467890774 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.45399049973954675 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.4694715627858908 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.48480962024633706 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.49999999999999994 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5150380749100542 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5299192642332049 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5446390350150271 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5591929034707469 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.573576436351046 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5877852522924731 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6018150231520483 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6156614753256582 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6293203910498374 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6427876096865393 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6560590289905072 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6691306063588582 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6819983600624985 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6946583704589973 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7071067811865475 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7193398003386511 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7313537016191705 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7431448254773942 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.754709580222772 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.766044443118978 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7771459614569708 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.788010753606722 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7986355100472928 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8090169943749475 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8191520442889918 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8290375725550417 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8386705679454239 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8480480961564261 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8571673007021122 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8660254037844386 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8746197071393957 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8829475928589269 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8910065241883678 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.898794046299167 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9063077870366499 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9135454576426009 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9205048534524403 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9271838545667874 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9335804264972017 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9396926207859083 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9455185755993167 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9510565162951535 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9563047559630354 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9612616959383189 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9659258262890683 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9702957262759965 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9743700647852352 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9781476007338056 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.981627183447664 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.984807753012208 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9876883405951378 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9902680687415703 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.992546151641322 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9945218953682733 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9961946980917455 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9975640502598242 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9986295347545738 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9993908270190958 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9998476951563913 * MATH_UNIT_FACTOR + 0.5), (int16_t) (1.0
* MATH_UNIT_FACTOR) };
 
const int16_t TAN_TABLE[] PROGMEM = {
(int16_t) (0.0 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.017455064928217585 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.03492076949174773 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.0524077792830412 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.06992681194351041 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.08748866352592401 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.10510423526567646 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.1227845609029046 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.14054083470239145 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.15838444032453627 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.17632698070846498 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.19438030913771848 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.2125565616700221 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.23086819112556312 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.24932800284318068 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.2679491924311227 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.2867453857588079 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.3057306814586604 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.3249196962329063 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.3443276132896652 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.36397023426620234 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.3838640350354158 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.4040262258351568 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.4244748162096047 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.4452286853085361 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.4663076581549986 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.48773258856586144 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5095254494944288 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5317094316614788 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.554309051452769 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5773502691896257 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6008606190275604 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6248693519093275 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6494075931975106 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6745085168424267 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7002075382097097 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7265425280053608 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7535540501027942 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7812856265067173 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.809784033195007 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8390996311772799 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8692867378162265 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9004040442978399 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9325150861376615 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9656887748070739 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9999999999999999 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.0355303137905694 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.0723687100246826 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.1106125148291928 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.1503684072210094 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.19175359259421 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.234897156535051 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.2799416321930788 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.3270448216204098 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.3763819204711734 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.4281480067421144 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.4825609685127403 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.5398649638145825 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.6003345290410504 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.6642794823505174 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.7320508075688767 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.8040477552714236 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.8807264653463318 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.9626105055051504 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.050303841579296 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.1445069205095586 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.2460367739042164 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.355852365823752 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.4750868534162964 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.6050890646938005 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.7474774194546216 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.904210877675822 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (3.0776835371752527 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (3.2708526184841404 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (3.4874144438409087 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (3.7320508075688776 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (4.010780933535842 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (4.331475874284157 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (4.704630109478451 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (5.144554015970307 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (5.671281819617707 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (6.313751514675041 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (7.115369722384195 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (8.144346427974593 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (9.514364454222587 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (11.430052302761348 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (14.300666256711896 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (19.08113668772816 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (28.636253282915515 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (57.289961630759876 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (32767)
};
const int16_t TAN_TABLE[] PROGMEM
= { (int16_t) (0.0 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.017455064928217585 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.03492076949174773 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.0524077792830412 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.06992681194351041 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.08748866352592401 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.10510423526567646 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.1227845609029046 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.14054083470239145 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.15838444032453627 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.17632698070846498 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.19438030913771848 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.2125565616700221 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.23086819112556312 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.24932800284318068 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.2679491924311227 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.2867453857588079 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.3057306814586604 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.3249196962329063 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.3443276132896652 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.36397023426620234 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.3838640350354158 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.4040262258351568 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.4244748162096047 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.4452286853085361 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.4663076581549986 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.48773258856586144 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5095254494944288 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5317094316614788 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.554309051452769 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.5773502691896257 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6008606190275604 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6248693519093275 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6494075931975106 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.6745085168424267 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7002075382097097 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7265425280053608 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7535540501027942 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.7812856265067173 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.809784033195007 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8390996311772799 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.8692867378162265 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9004040442978399 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9325150861376615 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9656887748070739 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (0.9999999999999999 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.0355303137905694 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.0723687100246826 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.1106125148291928 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.1503684072210094 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.19175359259421 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.234897156535051 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.2799416321930788 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.3270448216204098 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.3763819204711734 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.4281480067421144 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.4825609685127403 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.5398649638145825 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.6003345290410504 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.6642794823505174 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.7320508075688767 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.8040477552714236 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.8807264653463318 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (1.9626105055051504 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.050303841579296 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.1445069205095586 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.2460367739042164 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.355852365823752 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.4750868534162964 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.6050890646938005 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.7474774194546216 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (2.904210877675822 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (3.0776835371752527 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (3.2708526184841404 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (3.4874144438409087 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (3.7320508075688776 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (4.010780933535842 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (4.331475874284157 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (4.704630109478451 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (5.144554015970307 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (5.671281819617707 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (6.313751514675041 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (7.115369722384195 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (8.144346427974593 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (9.514364454222587 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (11.430052302761348 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (14.300666256711896 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (19.08113668772816 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (28.636253282915515 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (57.289961630759876 * MATH_UNIT_FACTOR + 0.5),
(int16_t) (32767) };
 
int16_t int_sin(int32_t arg) {
int8_t sign;
int16_t result;
arg /= MATH_DRG_FACTOR;
arg %= 360;
if (arg < 0) {
arg = -arg;
sign = -1;
} else {
sign = 1;
}
if (arg >= 90) {
arg = 180 - arg;
}
result = pgm_read_word(&SIN_TABLE[(uint8_t) arg]);
return (sign == 1) ? result : -result;
int8_t sign;
int16_t result;
arg /= MATH_DRG_FACTOR;
arg %= 360;
if (arg < 0) {
arg = -arg;
sign = -1;
} else {
sign = 1;
}
if (arg >= 90) {
arg = 180 - arg;
}
result = pgm_read_word(&SIN_TABLE[(uint8_t) arg]);
return (sign == 1) ? result : -result;
}
 
int16_t int_cos(int32_t arg) {
if (arg > 90L * MATH_DRG_FACTOR)
return int_sin(arg + (90L - 360L) * MATH_DRG_FACTOR);
return int_sin(arg + 90L * MATH_DRG_FACTOR);
if (arg > 90L * MATH_DRG_FACTOR)
return int_sin(arg + (90L - 360L) * MATH_DRG_FACTOR);
return int_sin(arg + 90L * MATH_DRG_FACTOR);
}
 
int16_t int_tan(int32_t arg) {
int8_t sign = 1;
int16_t result;
arg /= MATH_DRG_FACTOR;
if (arg >= 90) {
arg = 180 - arg;
sign = -1;
} else if (arg < -90) {
arg += 180;
} else if (arg < 0) {
arg =- arg;
sign = -1;
}
result = pgm_read_word(&TAN_TABLE[(uint8_t) arg]);
return (sign == 1) ? result : -result;
int8_t sign = 1;
int16_t result;
arg /= MATH_DRG_FACTOR;
if (arg >= 90) {
arg = 180 - arg;
sign = -1;
} else if (arg < -90) {
arg += 180;
} else if (arg < 0) {
arg = -arg;
sign = -1;
}
result = pgm_read_word(&TAN_TABLE[(uint8_t) arg]);
return (sign == 1) ? result : -result;
}
/branches/dongfang_FC_rewrite/dsl.c
2,88 → 2,87
// This code has been derived from the implementation of Stefan Engelke.
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
/*
Copyright (c) 2008 Stefan Engelke <stefan@tinkerer.eu>
Copyright (c) 2008 Stefan Engelke <stefan@tinkerer.eu>
 
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use, copy,
modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
 
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
 
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
 
$Id: rcdsl.c 60 2008-08-21 07:50:48Z taser $
$Id: rcdsl.c 60 2008-08-21 07:50:48Z taser $
 
RCDSL.H and RCDSL.C is an INOFFICIAL implementation of the
communication protocol used by DSL receivers of Act Europe.
The DSL receivers have a serial communication port to connect
two receivers in diversity mode. Each receiver is sending the
received servo signals periodically over this port. This fact
can be used to connect the receiver to the control unit of the
model via UART instead of evaluating the PPM signal.
RCDSL.H and RCDSL.C is an INOFFICIAL implementation of the
communication protocol used by DSL receivers of Act Europe.
The DSL receivers have a serial communication port to connect
two receivers in diversity mode. Each receiver is sending the
received servo signals periodically over this port. This fact
can be used to connect the receiver to the control unit of the
model via UART instead of evaluating the PPM signal.
 
If you have any questions, fell free to send me an e-mail.
If you have any questions, fell free to send me an e-mail.
 
*/
*/
 
 
/*
Connection of DSL to SV1 of FC:
( DSL Pin1 is on side of channel 4 )
Connection of DSL to SV1 of FC:
( DSL Pin1 is on side of channel 4 )
 
1. GND <--> pin 7 (GND)
2. TXD <--> pin 3 (RXD1 Atmega644p)
3. RXD <--> pin 4 (TXD1 Atmega644p) optional
4. 5V <--> pin 2 (5V)
1. GND <--> pin 7 (GND)
2. TXD <--> pin 3 (RXD1 Atmega644p)
3. RXD <--> pin 4 (TXD1 Atmega644p) optional
4. 5V <--> pin 2 (5V)
 
Do not connect the receiver via PPM-Sumsignal output the same time.
Do not connect the receiver via PPM-Sumsignal output the same time.
 
Data are send at every 20 ms @ 38400 Baud 8-N-1
Data are send at every 20 ms @ 38400 Baud 8-N-1
 
Data Frame: |0xFF|0xFF|0x1F|FREQALLOC|??|RSSI|VBAT|??|CRC|10|CH0D1|CH0D0|CH1D1|CH1D0|CRC| ...etc
Data Frame: |0xFF|0xFF|0x1F|FREQALLOC|??|RSSI|VBAT|??|CRC|10|CH0D1|CH0D0|CH1D1|CH1D0|CRC| ...etc
 
FREQALLOC = 35, 40, 72
RSSI = 0.. 255 // Received signal strength indicator
VBAT = 0...255 // supply voltage (0.0V.. 7.8V)
FREQALLOC = 35, 40, 72
RSSI = 0.. 255 // Received signal strength indicator
VBAT = 0...255 // supply voltage (0.0V.. 7.8V)
 
Servo Pair: |0x1X|CHXD1|CHXD0|CHX+1D1|CHX+1D0|CRC|
X is channel index of 1 servo value
D1D0 is servo value as u16 in range of 7373 (1ms) to 14745 (2ms)
there are 8 channels submitted, i.e 4 servo pairs
Servo Pair: |0x1X|CHXD1|CHXD0|CHX+1D1|CHX+1D0|CRC|
X is channel index of 1 servo value
D1D0 is servo value as u16 in range of 7373 (1ms) to 14745 (2ms)
there are 8 channels submitted, i.e 4 servo pairs
 
 
Frame examples with signel received
Frame examples with signel received
 
FFFF 1F23F079A304AD 1036012B1E6F 122AFB2AECB2 142B4D2B4404 1636872B33CE
FFFF 1F23F079A304AD 1036002B1F6F 122AFE2AEBB0 142B4B2B4406 1636872B33CE
FFFF 1F23F079A304AD 1035FF2B226E 122AFC2AEAB3 142B4E2B4304 1636882B33CD
FFFF 1F23F079A304AD 1036022B1E6E 122AFB2AEEB0 142B4A2B4506 1636872B33CE
FFFF 1F23F079A304AD 1036022B1E6E 122AFE2AEBB0 142B4B2B4406 1636882B33CD
FFFF 1F23F079A304AD 1036012B1E6F 122AFD2AEAB2 142B4E2B4403 1636862B33CF
FFFF 1F23F079A304AD 1036032B1D6E 122AFD2AEBB1 142B4C2B4504 1636862B33CF
FFFF 1F23F079A304AD 1036012B1E6F 122AFB2AECB2 142B4D2B4404 1636872B33CE
FFFF 1F23F079A304AD 1036002B1F6F 122AFE2AEBB0 142B4B2B4406 1636872B33CE
FFFF 1F23F079A304AD 1035FF2B226E 122AFC2AEAB3 142B4E2B4304 1636882B33CD
FFFF 1F23F079A304AD 1036022B1E6E 122AFB2AEEB0 142B4A2B4506 1636872B33CE
FFFF 1F23F079A304AD 1036022B1E6E 122AFE2AEBB0 142B4B2B4406 1636882B33CD
FFFF 1F23F079A304AD 1036012B1E6F 122AFD2AEAB2 142B4E2B4403 1636862B33CF
FFFF 1F23F079A304AD 1036032B1D6E 122AFD2AEBB1 142B4C2B4504 1636862B33CF
 
Frame examples with no signal received
Frame examples with no signal received
 
FFFF 1F23F000A30426
FFFF 1F23F000A30426
FFFF 1F23F000A30426
FFFF 1F23F000A30426
FFFF 1F23F000A30426
FFFF 1F23F000A30426
FFFF 1F23F000A30426
*/
FFFF 1F23F000A30426
FFFF 1F23F000A30426
FFFF 1F23F000A30426
FFFF 1F23F000A30426
FFFF 1F23F000A30426
FFFF 1F23F000A30426
FFFF 1F23F000A30426
*/
 
#include <stdlib.h>
#include "dsl.h"
96,47 → 95,48
uint8_t PacketBuffer[6];
//uint8_t Jitter = 0; // same measurement as RC_Quality in rc.c
 
typedef union
{
typedef union {
int16_t Servo[2];
uint8_t byte[4];
uint8_t byte[4];
} ChannelPair_t;
 
ChannelPair_t ChannelPair;
 
 
// This function is called, when a new servo signal is properly received.
// Parameters: servo - servo number (0-9)
// signal - servo signal between 7373 (1ms) and 14745 (2ms)
void dsl_new_signal(uint8_t channel, int16_t signal)
{
int16_t tmp;
uint8_t index = channel + 1; // mk channels start with 1
void dsl_new_signal(uint8_t channel, int16_t signal) {
int16_t tmp;
uint8_t index = channel + 1; // mk channels start with 1
 
//RC_Quality = (212 * (uint16_t)dsl_RSSI) / 128; // have to be scaled approx. by a factor of 1.66 to get 200 at full level
//if(RC_Quality > 255) RC_Quality = 255;
 
// signal from DSL-receiver is between 7373 (1ms) und 14745 (2ms).
signal-= 11059; // shift to neutral
signal/= 24; // scale to mk rc resolution
// signal from DSL-receiver is between 7373 (1ms) und 14745 (2ms).
signal -= 11059; // shift to neutral
signal /= 24; // scale to mk rc resolution
 
if(abs(signal-PPM_in[index]) < 6)
{
if(RC_Quality < 200) RC_Quality +=10;
else RC_Quality = 200;
if (abs(signal-PPM_in[index]) < 6) {
if (RC_Quality < 200)
RC_Quality += 10;
else
RC_Quality = 200;
}
 
// calculate exponential history for signal
// calculate exponential history for signal
tmp = (3 * (PPM_in[index]) + signal) / 4;
if(tmp > signal+1) tmp--; else
if(tmp < signal-1) tmp++;
if (tmp > signal + 1)
tmp--;
else if (tmp < signal - 1)
tmp++;
// calculate signal difference on good signal level
if(RC_Quality >= 195) PPM_diff[index] = ((tmp - PPM_in[index]) / 3) * 3; // cut off lower 3 bit for noise reduction
else PPM_diff[index] = 0;
if (RC_Quality >= 195)
PPM_diff[index] = ((tmp - PPM_in[index]) / 3) * 3; // cut off lower 3 bit for noise reduction
else
PPM_diff[index] = 0;
PPM_in[index] = tmp; // update channel value
 
if(index == 4)
{
if (index == 4) {
NewPpmData = 0;
}
}
143,34 → 143,29
 
// This function is called within dsl_parser(), when a complete
// data packet with valid checksum has been received.
void dsl_decode_packet(void)
{
uint8_t i;
void dsl_decode_packet(void) {
uint8_t i;
 
// check for header condition
if((PacketBuffer[0] & 0xF0) == 0x10)
{
if(PacketBuffer[0] == 0x1F) // separate status frame
if ((PacketBuffer[0] & 0xF0) == 0x10) {
if (PacketBuffer[0] == 0x1F) // separate status frame
{
dsl_Allocation = PacketBuffer[1]; // Get frequency allocation
dsl_Allocation = PacketBuffer[1]; // Get frequency allocation
// ?? = PacketBuffer[2];
dsl_RSSI = PacketBuffer[3]; // Get signal quality
dsl_Battery = PacketBuffer[4]; // Get voltage of battery supply
dsl_RSSI = PacketBuffer[3]; // Get signal quality
dsl_Battery = PacketBuffer[4]; // Get voltage of battery supply
// ?? = PacketBuffer[5];
if(dsl_RSSI == 0)
{
if (dsl_RSSI == 0) {
RC_Quality = 0;
for (i = 0; i<5; i++)
{
for (i = 0; i < 5; i++) {
PPM_diff[i] = 0;
PPM_in[i] = 0;
}
}
}
else // probably a channel pair
} else // probably a channel pair
{
i = PacketBuffer[0] & 0x0F; // last 4 bits of the header indicates the channel pair
if(i < 10)// maximum 12 channels
i = PacketBuffer[0] & 0x0F; // last 4 bits of the header indicates the channel pair
if (i < 10)// maximum 12 channels
{
// big to little endian
ChannelPair.byte[1] = PacketBuffer[1];
177,47 → 172,47
ChannelPair.byte[0] = PacketBuffer[2];
ChannelPair.byte[3] = PacketBuffer[3];
ChannelPair.byte[2] = PacketBuffer[4];
dsl_new_signal(i, ChannelPair.Servo[0]);
dsl_new_signal(i+1,ChannelPair.Servo[1]);
dsl_new_signal(i, ChannelPair.Servo[0]);
dsl_new_signal(i + 1, ChannelPair.Servo[1]);
}
}
} // EOF header condition
}
 
 
// this function should be called within the UART RX ISR
void dsl_parser(uint8_t c)
{
void dsl_parser(uint8_t c) {
static uint8_t last_c = 0;
static uint8_t crc = 0;
static uint8_t crc = 0;
static uint8_t cnt = 0;
static uint8_t packet_len = 0;
 
// check for sync condition
if ((c==0xFF) && (last_c==0xFF))
{
if ((c == 0xFF) && (last_c == 0xFF)) {
cnt = 0; // reset byte counter
crc = 0; // reset checksum
return;
}
}
 
if(cnt == 0) // begin of a packet
if (cnt == 0) // begin of a packet
{
if(c == 0x1F) packet_len = 5; // a status packet has 5 bytes + crc
else packet_len = 4; // a channel pair packet has 4 bytes + crc
if (c == 0x1F)
packet_len = 5; // a status packet has 5 bytes + crc
else
packet_len = 4; // a channel pair packet has 4 bytes + crc
}
if(cnt > packet_len) // packet complete, crc byte received
if (cnt > packet_len) // packet complete, crc byte received
{
// calculate checksum
crc = ~crc;
if (crc == 0xFF) crc = 0xFE;
if (crc == 0xFF)
crc = 0xFE;
// if crc matches decode the packet
if (c == crc) dsl_decode_packet();
// handle next packet
cnt = 0;
crc = 0;
}
else // collect channel data bytes
if (c == crc)
dsl_decode_packet();
// handle next packet
cnt = 0;
crc = 0;
} else // collect channel data bytes
{
PacketBuffer[cnt++] = c;
crc += c;
/branches/dongfang_FC_rewrite/dsl.h
3,8 → 3,8
 
#include <inttypes.h>
 
extern uint8_t dsl_RSSI; // Received signal strength indicator
extern uint8_t dsl_Battery; // Battery voltage (0-255 [0V - 8.2V])
extern uint8_t dsl_RSSI; // Received signal strength indicator
extern uint8_t dsl_Battery; // Battery voltage (0-255 [0V - 8.2V])
extern uint8_t dsl_Allocation; // Frequency allocation (35,40,72)
 
#define USART1_BAUD 38400
12,4 → 12,3
extern void dsl_parser(uint8_t c);
 
#endif //_DSL_H
 
/branches/dongfang_FC_rewrite/eeprom.c
74,10 → 74,10
#include "sensors.h"
 
// byte array in eeprom
uint8_t EEPromArray[E2END+1] EEMEM;
uint8_t EEPromArray[E2END + 1] EEMEM;
 
paramset_t staticParams;
MixerTable_t Mixer;
paramset_t staticParams;
MixerTable_t Mixer;
 
/*
* Default for your own experiments here, so you don't have to reset them
84,90 → 84,90
* from MK-Tool all the time.
*/
void setDefaultUserParams(void) {
uint8_t i;
for (i=0; i<sizeof(staticParams.UserParams1); i++) {
staticParams.UserParams1[i] = 0;
}
for (i=0; i<sizeof(staticParams.UserParams2); i++) {
staticParams.UserParams2[i] = 0;
}
/*
* While we are still using userparams for flight parameters, do set
* some safe & meaningful default values.
*/
staticParams.UserParams1[3] = 8; // Throttle stick D=8
staticParams.UserParams2[0] = 0b11010101; // All gyro filter constants 2; acc. 4
staticParams.UserParams2[1] = 2; // H&I motor smoothing.
staticParams.UserParams2[2] = 120; // Yaw I factor
staticParams.UserParams2[3] = 10; // Max Z acceleration for acc. correction of angles.
uint8_t i;
for (i = 0; i < sizeof(staticParams.UserParams1); i++) {
staticParams.UserParams1[i] = 0;
}
for (i = 0; i < sizeof(staticParams.UserParams2); i++) {
staticParams.UserParams2[i] = 0;
}
/*
* While we are still using userparams for flight parameters, do set
* some safe & meaningful default values.
*/
staticParams.UserParams1[3] = 8; // Throttle stick D=8
staticParams.UserParams2[0] = 0b11010101; // All gyro filter constants 2; acc. 4
staticParams.UserParams2[1] = 2; // H&I motor smoothing.
staticParams.UserParams2[2] = 120; // Yaw I factor
staticParams.UserParams2[3] = 10; // Max Z acceleration for acc. correction of angles.
}
 
void setOtherDefaults(void) {
/* Channel assignments were changed to the normal:
* Aileron/roll=1, elevator/pitch=2, throttle=3, yaw/rudder=4
*/
staticParams.ChannelAssignment[CH_PITCH] = 2;
staticParams.ChannelAssignment[CH_ROLL] = 1;
staticParams.ChannelAssignment[CH_THROTTLE] = 3;
staticParams.ChannelAssignment[CH_YAW] = 4;
staticParams.ChannelAssignment[CH_POTS+0] = 5;
staticParams.ChannelAssignment[CH_POTS+1] = 6;
staticParams.ChannelAssignment[CH_POTS+2] = 7;
staticParams.ChannelAssignment[CH_POTS+3] = 8;
staticParams.GlobalConfig = CFG_AXIS_COUPLING_ACTIVE | CFG_HEADING_HOLD; // CFG_COMPASS_ACTIVE | CFG_GPS_ACTIVE;//CFG_HEIGHT_CONTROL | CFG_HEIGHT_SWITCH | CFG_COMPASS_FIX;
staticParams.HeightMinGas = 30;
staticParams.MaxHeight = 251;
staticParams.HeightP = 10;
staticParams.HeightD = 30;
staticParams.Height_ACC_Effect = 30;
staticParams.Height_Gain = 4;
staticParams.StickP = 8;
staticParams.StickD = 12;
staticParams.StickYawP = 12;
staticParams.MinThrottle = 8;
staticParams.MaxThrottle = 230;
staticParams.CompassYawEffect = 128;
staticParams.GyroP = 80;
staticParams.GyroI = 100;
staticParams.LowVoltageWarning = 95;
staticParams.EmergencyGas = 35;
staticParams.EmergencyGasDuration = 30;
staticParams.Unused0 = 0;
staticParams.IFactor = 32;
staticParams.ServoPitchControl = 100;
staticParams.ServoPitchComp = 40;
staticParams.ServoPitchCompInvert = 0;
staticParams.ServoPitchMin = 50;
staticParams.ServoPitchMax = 150;
staticParams.ServoRefresh = 5;
staticParams.LoopGasLimit = 50;
staticParams.LoopThreshold = 90;
staticParams.LoopHysteresis = 50;
staticParams.BitConfig = 0;
staticParams.AxisCoupling1 = 90;
staticParams.AxisCoupling2 = 67;
staticParams.AxisCouplingYawCorrection = 0;
staticParams.DynamicStability = 50;
staticParams.J16Bitmask = 95;
staticParams.J17Bitmask = 243;
staticParams.J16Timing = 15;
staticParams.J17Timing = 15;
staticParams.NaviGpsModeControl = 253;
staticParams.NaviGpsGain = 100;
staticParams.NaviGpsP = 90;
staticParams.NaviGpsI = 90;
staticParams.NaviGpsD = 90;
staticParams.NaviGpsPLimit = 75;
staticParams.NaviGpsILimit = 75;
staticParams.NaviGpsDLimit = 75;
staticParams.NaviGpsACC = 0;
staticParams.NaviGpsMinSat = 6;
staticParams.NaviStickThreshold = 8;
staticParams.NaviWindCorrection = 90;
staticParams.NaviSpeedCompensation = 30;
staticParams.NaviOperatingRadius = 100;
staticParams.NaviAngleLimitation = 100;
staticParams.NaviPHLoginTime = 4;
/* Channel assignments were changed to the normal:
* Aileron/roll=1, elevator/pitch=2, throttle=3, yaw/rudder=4
*/
staticParams.ChannelAssignment[CH_PITCH] = 2;
staticParams.ChannelAssignment[CH_ROLL] = 1;
staticParams.ChannelAssignment[CH_THROTTLE] = 3;
staticParams.ChannelAssignment[CH_YAW] = 4;
staticParams.ChannelAssignment[CH_POTS + 0] = 5;
staticParams.ChannelAssignment[CH_POTS + 1] = 6;
staticParams.ChannelAssignment[CH_POTS + 2] = 7;
staticParams.ChannelAssignment[CH_POTS + 3] = 8;
staticParams.GlobalConfig = CFG_AXIS_COUPLING_ACTIVE | CFG_HEADING_HOLD; // CFG_COMPASS_ACTIVE | CFG_GPS_ACTIVE;//CFG_HEIGHT_CONTROL | CFG_HEIGHT_SWITCH | CFG_COMPASS_FIX;
staticParams.HeightMinGas = 30;
staticParams.MaxHeight = 251;
staticParams.HeightP = 10;
staticParams.HeightD = 30;
staticParams.Height_ACC_Effect = 30;
staticParams.Height_Gain = 4;
staticParams.StickP = 8;
staticParams.StickD = 12;
staticParams.StickYawP = 12;
staticParams.MinThrottle = 8;
staticParams.MaxThrottle = 230;
staticParams.CompassYawEffect = 128;
staticParams.GyroP = 80;
staticParams.GyroI = 100;
staticParams.LowVoltageWarning = 95;
staticParams.EmergencyGas = 35;
staticParams.EmergencyGasDuration = 30;
staticParams.Unused0 = 0;
staticParams.IFactor = 32;
staticParams.ServoPitchControl = 100;
staticParams.ServoPitchComp = 40;
staticParams.ServoPitchCompInvert = 0;
staticParams.ServoPitchMin = 50;
staticParams.ServoPitchMax = 150;
staticParams.ServoRefresh = 5;
staticParams.LoopGasLimit = 50;
staticParams.LoopThreshold = 90;
staticParams.LoopHysteresis = 50;
staticParams.BitConfig = 0;
staticParams.AxisCoupling1 = 90;
staticParams.AxisCoupling2 = 67;
staticParams.AxisCouplingYawCorrection = 0;
staticParams.DynamicStability = 50;
staticParams.J16Bitmask = 95;
staticParams.J17Bitmask = 243;
staticParams.J16Timing = 15;
staticParams.J17Timing = 15;
staticParams.NaviGpsModeControl = 253;
staticParams.NaviGpsGain = 100;
staticParams.NaviGpsP = 90;
staticParams.NaviGpsI = 90;
staticParams.NaviGpsD = 90;
staticParams.NaviGpsPLimit = 75;
staticParams.NaviGpsILimit = 75;
staticParams.NaviGpsDLimit = 75;
staticParams.NaviGpsACC = 0;
staticParams.NaviGpsMinSat = 6;
staticParams.NaviStickThreshold = 8;
staticParams.NaviWindCorrection = 90;
staticParams.NaviSpeedCompensation = 30;
staticParams.NaviOperatingRadius = 100;
staticParams.NaviAngleLimitation = 100;
staticParams.NaviPHLoginTime = 4;
}
 
/***************************************************/
174,11 → 174,12
/* Default Values for parameter set 1 */
/***************************************************/
void ParamSet_DefaultSet1(void) { // sport
setOtherDefaults();
gyro_setDefaults();
setDefaultUserParams();
staticParams.GlobalConfig = CFG_ROTARY_RATE_LIMITER | CFG_AXIS_COUPLING_ACTIVE;
memcpy(staticParams.Name, "Sport\0",6);
setOtherDefaults();
gyro_setDefaults();
setDefaultUserParams();
staticParams.GlobalConfig = CFG_ROTARY_RATE_LIMITER
| CFG_AXIS_COUPLING_ACTIVE;
memcpy(staticParams.Name, "Sport\0", 6);
}
 
/***************************************************/
185,14 → 186,15
/* Default Values for parameter set 2 */
/***************************************************/
void ParamSet_DefaultSet2(void) { // normal
setOtherDefaults();
gyro_setDefaults();
setDefaultUserParams();
staticParams.GlobalConfig = CFG_ROTARY_RATE_LIMITER | CFG_AXIS_COUPLING_ACTIVE;
staticParams.Height_Gain = 3;
staticParams.J16Timing = 20;
staticParams.J17Timing = 20;
memcpy(staticParams.Name, "Normal\0", 7);
setOtherDefaults();
gyro_setDefaults();
setDefaultUserParams();
staticParams.GlobalConfig = CFG_ROTARY_RATE_LIMITER
| CFG_AXIS_COUPLING_ACTIVE;
staticParams.Height_Gain = 3;
staticParams.J16Timing = 20;
staticParams.J17Timing = 20;
memcpy(staticParams.Name, "Normal\0", 7);
}
 
/***************************************************/
199,16 → 201,17
/* Default Values for parameter set 3 */
/***************************************************/
void ParamSet_DefaultSet3(void) { // beginner
setOtherDefaults();
gyro_setDefaults();
setDefaultUserParams();
staticParams.GlobalConfig = CFG_ROTARY_RATE_LIMITER | CFG_AXIS_COUPLING_ACTIVE;
staticParams.Height_Gain = 3;
staticParams.EmergencyGasDuration = 20;
staticParams.AxisCouplingYawCorrection = 70;
staticParams.J16Timing = 30;
staticParams.J17Timing = 30;
memcpy(staticParams.Name, "Beginner\0", 9);
setOtherDefaults();
gyro_setDefaults();
setDefaultUserParams();
staticParams.GlobalConfig = CFG_ROTARY_RATE_LIMITER
| CFG_AXIS_COUPLING_ACTIVE;
staticParams.Height_Gain = 3;
staticParams.EmergencyGasDuration = 20;
staticParams.AxisCouplingYawCorrection = 70;
staticParams.J16Timing = 30;
staticParams.J17Timing = 30;
memcpy(staticParams.Name, "Beginner\0", 9);
}
 
/***************************************************/
215,7 → 218,7
/* Read Parameter from EEPROM as byte */
/***************************************************/
uint8_t GetParamByte(uint16_t param_id) {
return eeprom_read_byte(&EEPromArray[EEPROM_ADR_PARAM_BEGIN + param_id]);
return eeprom_read_byte(&EEPromArray[EEPROM_ADR_PARAM_BEGIN + param_id]);
}
 
/***************************************************/
222,7 → 225,7
/* Write Parameter to EEPROM as byte */
/***************************************************/
void SetParamByte(uint16_t param_id, uint8_t value) {
eeprom_write_byte(&EEPromArray[EEPROM_ADR_PARAM_BEGIN + param_id], value);
eeprom_write_byte(&EEPromArray[EEPROM_ADR_PARAM_BEGIN + param_id], value);
}
 
/***************************************************/
229,7 → 232,8
/* Read Parameter from EEPROM as word */
/***************************************************/
uint16_t GetParamWord(uint16_t param_id) {
return eeprom_read_word((uint16_t *) &EEPromArray[EEPROM_ADR_PARAM_BEGIN + param_id]);
return eeprom_read_word((uint16_t *) &EEPromArray[EEPROM_ADR_PARAM_BEGIN
+ param_id]);
}
 
/***************************************************/
236,7 → 240,8
/* Write Parameter to EEPROM as word */
/***************************************************/
void SetParamWord(uint16_t param_id, uint16_t value) {
eeprom_write_word((uint16_t *) &EEPromArray[EEPROM_ADR_PARAM_BEGIN + param_id], value);
eeprom_write_word(
(uint16_t *) &EEPromArray[EEPROM_ADR_PARAM_BEGIN + param_id], value);
}
 
/***************************************************/
244,9 → 249,12
/***************************************************/
// number [1..5]
void ParamSet_ReadFromEEProm(uint8_t setnumber) {
if((1 > setnumber) || (setnumber > 5)) setnumber = 3;
eeprom_read_block((uint8_t *) &staticParams.ChannelAssignment[0], &EEPromArray[EEPROM_ADR_PARAMSET_BEGIN + PARAMSET_STRUCT_LEN * (setnumber - 1)], PARAMSET_STRUCT_LEN);
output_init();
if ((1 > setnumber) || (setnumber > 5))
setnumber = 3;
eeprom_read_block((uint8_t *) &staticParams.ChannelAssignment[0],
&EEPromArray[EEPROM_ADR_PARAMSET_BEGIN + PARAMSET_STRUCT_LEN * (setnumber
- 1)], PARAMSET_STRUCT_LEN);
output_init();
}
 
/***************************************************/
254,14 → 262,20
/***************************************************/
// number [1..5]
void ParamSet_WriteToEEProm(uint8_t setnumber) {
if(setnumber > 5) setnumber = 5;
if(setnumber < 1) return;
eeprom_write_block((uint8_t *) &staticParams.ChannelAssignment[0], &EEPromArray[EEPROM_ADR_PARAMSET_BEGIN + PARAMSET_STRUCT_LEN * (setnumber - 1)], PARAMSET_STRUCT_LEN);
eeprom_write_word((uint16_t *) &EEPromArray[EEPROM_ADR_PARAMSET_LENGTH], PARAMSET_STRUCT_LEN);
eeprom_write_block( &staticParams.ChannelAssignment[0], &EEPromArray[EEPROM_ADR_CHANNELS], 8); // backup the first 8 bytes that is the rc channel mapping
// set this parameter set to active set
setActiveParamSet(setnumber);
output_init();
if (setnumber > 5)
setnumber = 5;
if (setnumber < 1)
return;
eeprom_write_block((uint8_t *) &staticParams.ChannelAssignment[0],
&EEPromArray[EEPROM_ADR_PARAMSET_BEGIN + PARAMSET_STRUCT_LEN * (setnumber
- 1)], PARAMSET_STRUCT_LEN);
eeprom_write_word((uint16_t *) &EEPromArray[EEPROM_ADR_PARAMSET_LENGTH],
PARAMSET_STRUCT_LEN);
eeprom_write_block(&staticParams.ChannelAssignment[0],
&EEPromArray[EEPROM_ADR_CHANNELS], 8); // backup the first 8 bytes that is the rc channel mapping
// set this parameter set to active set
setActiveParamSet(setnumber);
output_init();
}
 
/***************************************************/
268,13 → 282,13
/* Get active parameter set */
/***************************************************/
uint8_t getActiveParamSet(void) {
uint8_t setnumber;
setnumber = eeprom_read_byte(&EEPromArray[PID_ACTIVE_SET]);
if(setnumber > 5) {
setnumber = 3;
eeprom_write_byte(&EEPromArray[PID_ACTIVE_SET], setnumber);
}
return(setnumber);
uint8_t setnumber;
setnumber = eeprom_read_byte(&EEPromArray[PID_ACTIVE_SET]);
if (setnumber > 5) {
setnumber = 3;
eeprom_write_byte(&EEPromArray[PID_ACTIVE_SET], setnumber);
}
return (setnumber);
}
 
/***************************************************/
281,9 → 295,11
/* Set active parameter set */
/***************************************************/
void setActiveParamSet(uint8_t setnumber) {
if(setnumber > 5) setnumber = 5;
if(setnumber < 1) setnumber = 1;
eeprom_write_byte(&EEPromArray[PID_ACTIVE_SET], setnumber);
if (setnumber > 5)
setnumber = 5;
if (setnumber < 1)
setnumber = 1;
eeprom_write_byte(&EEPromArray[PID_ACTIVE_SET], setnumber);
}
 
/***************************************************/
290,11 → 306,13
/* Read MixerTable from EEPROM */
/***************************************************/
uint8_t MixerTable_ReadFromEEProm(void) {
if(eeprom_read_byte(&EEPromArray[EEPROM_ADR_MIXER_TABLE]) == EEMIXER_REVISION) {
eeprom_read_block((uint8_t *) &Mixer, &EEPromArray[EEPROM_ADR_MIXER_TABLE], sizeof(Mixer));
return 1;
}
else return 0;
if (eeprom_read_byte(&EEPromArray[EEPROM_ADR_MIXER_TABLE])
== EEMIXER_REVISION) {
eeprom_read_block((uint8_t *) &Mixer, &EEPromArray[EEPROM_ADR_MIXER_TABLE],
sizeof(Mixer));
return 1;
} else
return 0;
}
 
/***************************************************/
301,11 → 319,12
/* Write Mixer Table to EEPROM */
/***************************************************/
uint8_t MixerTable_WriteToEEProm(void) {
if(Mixer.Revision == EEMIXER_REVISION) {
eeprom_write_block((uint8_t *) &Mixer, &EEPromArray[EEPROM_ADR_MIXER_TABLE], sizeof(Mixer));
return 1;
}
else return 0;
if (Mixer.Revision == EEMIXER_REVISION) {
eeprom_write_block((uint8_t *) &Mixer,
&EEPromArray[EEPROM_ADR_MIXER_TABLE], sizeof(Mixer));
return 1;
} else
return 0;
}
 
/***************************************************/
312,21 → 331,25
/* Default Values for Mixer Table */
/***************************************************/
void MixerTable_Default(void) { // Quadro
uint8_t i;
Mixer.Revision = EEMIXER_REVISION;
// clear mixer table (but preset throttle)
for(i = 0; i < 16; i++) {
Mixer.Motor[i][MIX_THROTTLE] = i < 4 ? 64 : 0;
Mixer.Motor[i][MIX_PITCH] = 0;
Mixer.Motor[i][MIX_ROLL] = 0;
Mixer.Motor[i][MIX_YAW] = 0;
}
// default = Quadro
Mixer.Motor[0][MIX_PITCH] = +64; Mixer.Motor[0][MIX_YAW] = +64;
Mixer.Motor[1][MIX_PITCH] = -64; Mixer.Motor[1][MIX_YAW] = +64;
Mixer.Motor[2][MIX_ROLL] = -64; Mixer.Motor[2][MIX_YAW] = -64;
Mixer.Motor[3][MIX_ROLL] = +64; Mixer.Motor[3][MIX_YAW] = -64;
memcpy(Mixer.Name, "Quadro\0", 7);
uint8_t i;
Mixer.Revision = EEMIXER_REVISION;
// clear mixer table (but preset throttle)
for (i = 0; i < 16; i++) {
Mixer.Motor[i][MIX_THROTTLE] = i < 4 ? 64 : 0;
Mixer.Motor[i][MIX_PITCH] = 0;
Mixer.Motor[i][MIX_ROLL] = 0;
Mixer.Motor[i][MIX_YAW] = 0;
}
// default = Quadro
Mixer.Motor[0][MIX_PITCH] = +64;
Mixer.Motor[0][MIX_YAW] = +64;
Mixer.Motor[1][MIX_PITCH] = -64;
Mixer.Motor[1][MIX_YAW] = +64;
Mixer.Motor[2][MIX_ROLL] = -64;
Mixer.Motor[2][MIX_YAW] = -64;
Mixer.Motor[3][MIX_ROLL] = +64;
Mixer.Motor[3][MIX_YAW] = -64;
memcpy(Mixer.Name, "Quadro\0", 7);
}
 
/***************************************************/
333,62 → 356,64
/* Initialize EEPROM Parameter Sets */
/***************************************************/
void ParamSet_Init(void) {
uint8_t Channel_Backup=1, i, j;
// parameter version check
if(eeprom_read_byte(&EEPromArray[PID_PARAM_REVISION]) != EEPARAM_REVISION) {
// if version check faild
printf("\n\rInit Parameter in EEPROM");
eeprom_write_byte(&EEPromArray[EEPROM_ADR_MIXER_TABLE], 0xFF); // reset also mixer table
// check if channel mapping backup is valid
for (j=0; j<4 && Channel_Backup; j++) {
if (eeprom_read_byte(&EEPromArray[EEPROM_ADR_CHANNELS+0]) >= 12)
Channel_Backup = 0;
}
// fill all 5 parameter settings
for (i=1; i<6; i++) {
switch(i) {
case 1:
ParamSet_DefaultSet1(); // Fill staticParams Structure to default parameter set 1 (Sport)
break;
case 2:
ParamSet_DefaultSet2(); // Kamera
break;
case 3:
ParamSet_DefaultSet3(); // Beginner
break;
default:
ParamSet_DefaultSet2(); // Kamera
break;
}
if(Channel_Backup) { // if we have a rc channel mapping backup in eeprom
// restore it
for (j=0; j<8; j++) {
staticParams.ChannelAssignment[j] = eeprom_read_byte(&EEPromArray[EEPROM_ADR_CHANNELS+j]);
uint8_t Channel_Backup = 1, i, j;
// parameter version check
if (eeprom_read_byte(&EEPromArray[PID_PARAM_REVISION]) != EEPARAM_REVISION) {
// if version check faild
printf("\n\rInit Parameter in EEPROM");
eeprom_write_byte(&EEPromArray[EEPROM_ADR_MIXER_TABLE], 0xFF); // reset also mixer table
// check if channel mapping backup is valid
for (j = 0; j < 4 && Channel_Backup; j++) {
if (eeprom_read_byte(&EEPromArray[EEPROM_ADR_CHANNELS + 0]) >= 12)
Channel_Backup = 0;
}
// fill all 5 parameter settings
for (i = 1; i < 6; i++) {
switch (i) {
case 1:
ParamSet_DefaultSet1(); // Fill staticParams Structure to default parameter set 1 (Sport)
break;
case 2:
ParamSet_DefaultSet2(); // Kamera
break;
case 3:
ParamSet_DefaultSet3(); // Beginner
break;
default:
ParamSet_DefaultSet2(); // Kamera
break;
}
if (Channel_Backup) { // if we have a rc channel mapping backup in eeprom
// restore it
for (j = 0; j < 8; j++) {
staticParams.ChannelAssignment[j] = eeprom_read_byte(
&EEPromArray[EEPROM_ADR_CHANNELS + j]);
}
}
ParamSet_WriteToEEProm(i);
}
// default-Setting is parameter set 3
setActiveParamSet(1);
// update version info
SetParamByte(PID_PARAM_REVISION, EEPARAM_REVISION);
}
}
ParamSet_WriteToEEProm(i);
}
// default-Setting is parameter set 3
setActiveParamSet(1);
// update version info
SetParamByte(PID_PARAM_REVISION, EEPARAM_REVISION);
}
// read active parameter set to staticParams stucture
ParamSet_ReadFromEEProm(getActiveParamSet());
printf("\n\rUsing Parameter Set %d", getActiveParamSet());
// load mixer table
if(!MixerTable_ReadFromEEProm()) {
printf("\n\rGenerating default Mixer Table");
MixerTable_Default(); // Quadro
MixerTable_WriteToEEProm();
}
// determine motornumber
RequiredMotors = 0;
for(i = 0; i < 16; i++) {
if(Mixer.Motor[i][MIX_THROTTLE] > 0) RequiredMotors++;
}
printf("\n\rMixer-Config: '%s' (%u Motors)",Mixer.Name, RequiredMotors);
printf("\n\r==============================");
// read active parameter set to staticParams stucture
ParamSet_ReadFromEEProm(getActiveParamSet());
printf("\n\rUsing Parameter Set %d", getActiveParamSet());
 
// load mixer table
if (!MixerTable_ReadFromEEProm()) {
printf("\n\rGenerating default Mixer Table");
MixerTable_Default(); // Quadro
MixerTable_WriteToEEProm();
}
// determine motornumber
RequiredMotors = 0;
for (i = 0; i < 16; i++) {
if (Mixer.Motor[i][MIX_THROTTLE] > 0)
RequiredMotors++;
}
 
printf("\n\rMixer-Config: '%s' (%u Motors)",Mixer.Name, RequiredMotors);
printf("\n\r==============================");
}
/branches/dongfang_FC_rewrite/eeprom.h
11,16 → 11,12
#define PID_ACC_PITCH 4 // word
#define PID_ACC_ROLL 6 // word
#define PID_ACC_Z 8 // word
 
#define EEPROM_ADR_CHANNELS 80 // 8 bytes
 
#define EEPROM_ADR_PARAMSET_LENGTH 98 // word
#define EEPROM_ADR_PARAMSET_BEGIN 100
#define EEPROM_ADR_MIXER_TABLE 1000 // 1000 - 1076
 
#define EEPARAM_REVISION 75 // is count up, if paramater stucture has changed (compatibility)
#define EEMIXER_REVISION 1 // is count up, if Mixer stucture has changed (compatibility)
 
extern void ParamSet_Init(void);
extern void ParamSet_ReadFromEEProm(uint8_t setnumber);
extern void ParamSet_WriteToEEProm(uint8_t setnumber);
/branches/dongfang_FC_rewrite/externalControl.c
9,59 → 9,62
 
// TODO: Who is going to call this
void EC_setNeutral(void) {
// if necessary. From main.c.
externalControl.config = 0;
externalControl.pitch = 0;
externalControl.roll = 0;
externalControl.yaw = 0;
externalControl.throttle = 0;
// From main.c. What does it do??
externalControl.digital[0] = 0x55;
// if necessary. From main.c.
externalControl.config = 0;
externalControl.pitch = 0;
externalControl.roll = 0;
externalControl.yaw = 0;
externalControl.throttle = 0;
 
// From main.c. What does it do??
externalControl.digital[0] = 0x55;
}
 
int16_t* EC_getPRTY(void) {
return EC_PRTY;
return EC_PRTY;
}
 
uint8_t EC_getArgument(void) {
return externalControl.config;
return externalControl.config;
}
 
uint8_t EC_getCommand(void) {
return externalControl.free;
return externalControl.free;
}
 
// not implemented.
int16_t EC_getVariable(uint8_t varNum) {
return 0;
return 0;
}
 
void EC_update() {
if (externalControlActive) {
externalControlActive--;
EC_PRTY[CONTROL_PITCH] = (int16_t) externalControl.pitch * (int16_t) staticParams.StickP;
EC_PRTY[CONTROL_ROLL] = externalControl.roll * (int16_t) staticParams.StickP;
EC_PRTY[CONTROL_THROTTLE] = externalControl.throttle;
EC_PRTY[CONTROL_YAW] = externalControl.yaw; // No stickP or similar??????
} else {
EC_PRTY[CONTROL_PITCH] = EC_PRTY[CONTROL_ROLL] = EC_PRTY[CONTROL_THROTTLE] = EC_PRTY[CONTROL_YAW] = 0;
}
if (externalControlActive) {
externalControlActive--;
EC_PRTY[CONTROL_PITCH] = (int16_t) externalControl.pitch
* (int16_t) staticParams.StickP;
EC_PRTY[CONTROL_ROLL] = externalControl.roll
* (int16_t) staticParams.StickP;
EC_PRTY[CONTROL_THROTTLE] = externalControl.throttle;
EC_PRTY[CONTROL_YAW] = externalControl.yaw; // No stickP or similar??????
} else {
EC_PRTY[CONTROL_PITCH] = EC_PRTY[CONTROL_ROLL] = EC_PRTY[CONTROL_THROTTLE]
= EC_PRTY[CONTROL_YAW] = 0;
}
}
 
uint8_t EC_getSignalQuality(void) {
if (externalControlActive > 80)
// Configured and heard from recently
return SIGNAL_GOOD;
if (externalControlActive > 80)
// Configured and heard from recently
return SIGNAL_GOOD;
 
if (externalControlActive)
// Configured and heard from
return SIGNAL_OK;
if (externalControlActive)
// Configured and heard from
return SIGNAL_OK;
 
if (!(externalControl.config & 0x01 && dynamicParams.ExternalControl > 128))
// External control is not even configured.
return NO_SIGNAL;
if (!(externalControl.config & 0x01 && dynamicParams.ExternalControl > 128))
// External control is not even configured.
return NO_SIGNAL;
 
// Configured but expired.
return SIGNAL_LOST;
// Configured but expired.
return SIGNAL_LOST;
}
/branches/dongfang_FC_rewrite/externalControl.h
5,28 → 5,28
#include<inttypes.h>
 
typedef struct {
uint8_t digital[2];
uint8_t remoteButtons;
int8_t pitch;
int8_t roll;
int8_t yaw;
uint8_t throttle;
int8_t height;
uint8_t free; // Let's use that for commands now.
uint8_t frame;
uint8_t config; // Let's use that for arguemnts.
} __attribute__((packed)) ExternalControl_t;
uint8_t digital[2];
uint8_t remoteButtons;
int8_t pitch;
int8_t roll;
int8_t yaw;
uint8_t throttle;
int8_t height;
uint8_t free; // Let's use that for commands now.
uint8_t frame;
uint8_t config; // Let's use that for arguemnts.
}__attribute__((packed)) ExternalControl_t;
 
extern ExternalControl_t externalControl;
extern uint8_t externalControlActive;
 
void EC_update(void);
int16_t* EC_getPRTY(void);
uint8_t EC_getArgument(void);
uint8_t EC_getCommand(void);
int16_t EC_getVariable(uint8_t varNum);
void EC_calibrate(void);
uint8_t EC_getSignalQuality (void);
void EC_setNeutral(void);
void EC_update(void);
int16_t* EC_getPRTY(void);
uint8_t EC_getArgument(void);
uint8_t EC_getCommand(void);
int16_t EC_getVariable(uint8_t varNum);
void EC_calibrate(void);
uint8_t EC_getSignalQuality(void);
void EC_setNeutral(void);
 
#endif
/branches/dongfang_FC_rewrite/flexcontrol.h
1,8 → 1,8
typedef struct {
int16_t(*getPitch)(void);
int16_t(*getRoll)(void);
int16_t(*getYaw)(void);
uint16_t(*getThrottle)(void);
uint8_t isSignalGood(void);
uint8_t isSignalUnreadable(void);
int16_t(*getPitch)(void);
int16_t(*getRoll)(void);
int16_t(*getYaw)(void);
uint16_t(*getThrottle)(void);
uint8_t isSignalGood(void);
uint8_t isSignalUnreadable(void);
} t_control;
/branches/dongfang_FC_rewrite/flight.c
81,7 → 81,7
*/
// int16_t naviAccPitch = 0, naviAccRoll = 0, naviCntAcc = 0;
 
uint8_t gyroPFactor, gyroIFactor; // the PD factors for the attitude control
uint8_t gyroPFactor, gyroIFactor; // the PD factors for the attitude control
uint8_t yawPFactor, yawIFactor; // the PD factors for the yaw control
 
// Some integral weight constant...
95,23 → 95,24
/* Filter for motor value smoothing (necessary???) */
/************************************************************************/
int16_t motorFilter(int16_t newvalue, int16_t oldvalue) {
switch(dynamicParams.UserParams[5]) {
case 0:
return newvalue;
case 1:
return (oldvalue + newvalue) / 2;
case 2:
if(newvalue > oldvalue)
return (1 * (int16_t)oldvalue + newvalue) / 2; //mean of old and new
else
return newvalue - (oldvalue - newvalue) * 1; // 2 * new - old
case 3:
if(newvalue < oldvalue)
return (1 * (int16_t)oldvalue + newvalue) / 2; //mean of old and new
else
return newvalue - (oldvalue - newvalue) * 1; // 2 * new - old
default: return newvalue;
}
switch (dynamicParams.UserParams[5]) {
case 0:
return newvalue;
case 1:
return (oldvalue + newvalue) / 2;
case 2:
if (newvalue > oldvalue)
return (1 * (int16_t) oldvalue + newvalue) / 2; //mean of old and new
else
return newvalue - (oldvalue - newvalue) * 1; // 2 * new - old
case 3:
if (newvalue < oldvalue)
return (1 * (int16_t) oldvalue + newvalue) / 2; //mean of old and new
else
return newvalue - (oldvalue - newvalue) * 1; // 2 * new - old
default:
return newvalue;
}
}
 
/************************************************************************/
118,345 → 119,345
/* Neutral Readings */
/************************************************************************/
void flight_setNeutral() {
MKFlags |= MKFLAG_CALIBRATE;
MKFlags |= MKFLAG_CALIBRATE;
 
// not really used here any more.
dynamicParams.KalmanK = -1;
dynamicParams.KalmanMaxDrift = 0;
dynamicParams.KalmanMaxFusion = 32;
// not really used here any more.
dynamicParams.KalmanK = -1;
dynamicParams.KalmanMaxDrift = 0;
dynamicParams.KalmanMaxFusion = 32;
 
controlMixer_initVariables();
controlMixer_initVariables();
}
 
void setFlightParameters(uint8_t _Ki, uint8_t _gyroPFactor, uint8_t _gyroIFactor, uint8_t _yawPFactor, uint8_t _yawIFactor) {
Ki = 10300 / _Ki;
gyroPFactor = _gyroPFactor;
gyroIFactor = _gyroIFactor;
yawPFactor = _yawPFactor;
yawIFactor = _yawIFactor;
void setFlightParameters(uint8_t _Ki, uint8_t _gyroPFactor,
uint8_t _gyroIFactor, uint8_t _yawPFactor, uint8_t _yawIFactor) {
Ki = 10300 / _Ki;
gyroPFactor = _gyroPFactor;
gyroIFactor = _gyroIFactor;
yawPFactor = _yawPFactor;
yawIFactor = _yawIFactor;
}
 
void setNormalFlightParameters(void) {
setFlightParameters(dynamicParams.IFactor + 1,
dynamicParams.GyroP + 10,
staticParams.GlobalConfig & CFG_HEADING_HOLD ? 0 : dynamicParams.GyroI,
dynamicParams.GyroP + 10,
dynamicParams.UserParams[6]
);
setFlightParameters(dynamicParams.IFactor + 1, dynamicParams.GyroP + 10,
staticParams.GlobalConfig & CFG_HEADING_HOLD ? 0 : dynamicParams.GyroI,
dynamicParams.GyroP + 10, dynamicParams.UserParams[6]);
}
 
void setStableFlightParameters(void) {
setFlightParameters(33, 90, 120, 90, 120);
setFlightParameters(33, 90, 120, 90, 120);
}
 
 
/************************************************************************/
/* Main Flight Control */
/************************************************************************/
void flight_control(void) {
int16_t tmp_int;
// Mixer Fractions that are combined for Motor Control
int16_t yawTerm, throttleTerm, term[2];
int16_t tmp_int;
// Mixer Fractions that are combined for Motor Control
int16_t yawTerm, throttleTerm, term[2];
 
// PID controller variables
int16_t PDPart[2], PDPartYaw, PPart[2];
static int32_t IPart[2] = {0,0};
// static int32_t yawControlRate = 0;
// PID controller variables
int16_t PDPart[2], PDPartYaw, PPart[2];
static int32_t IPart[2] = { 0, 0 };
// static int32_t yawControlRate = 0;
 
// Removed. Too complicated, and apparently not necessary with MEMS gyros anyway.
// static int32_t IntegralGyroPitchError = 0, IntegralGyroRollError = 0;
// static int32_t CorrectionPitch, CorrectionRoll;
// Removed. Too complicated, and apparently not necessary with MEMS gyros anyway.
// static int32_t IntegralGyroPitchError = 0, IntegralGyroRollError = 0;
// static int32_t CorrectionPitch, CorrectionRoll;
 
static uint16_t emergencyFlightTime;
static int8_t debugDataTimer = 1;
static uint16_t emergencyFlightTime;
static int8_t debugDataTimer = 1;
 
// High resolution motor values for smoothing of PID motor outputs
static int16_t motorFilters[MAX_MOTORS];
// High resolution motor values for smoothing of PID motor outputs
static int16_t motorFilters[MAX_MOTORS];
 
uint8_t i, axis;
uint8_t i, axis;
 
controlMixer_update();
controlMixer_update();
 
// Fire the main flight attitude calculation, including integration of angles.
calculateFlightAttitude();
// Fire the main flight attitude calculation, including integration of angles.
calculateFlightAttitude();
 
throttleTerm = controlThrottle;
// This check removed. Is done on a per-motor basis, after output matrix multiplication.
// if(throttleTerm < staticParams.MinThrottle + 10) throttleTerm = staticParams.MinThrottle + 10;
// else if(throttleTerm > staticParams.MaxThrottle - 20) throttleTerm = (staticParams.MaxThrottle - 20);
throttleTerm = controlThrottle;
// This check removed. Is done on a per-motor basis, after output matrix multiplication.
// if(throttleTerm < staticParams.MinThrottle + 10) throttleTerm = staticParams.MinThrottle + 10;
// else if(throttleTerm > staticParams.MaxThrottle - 20) throttleTerm = (staticParams.MaxThrottle - 20);
 
/************************************************************************/
/* RC-signal is bad */
/* This part could be abstracted, as having yet another control input */
/* to the control mixer: An emergency autopilot control. */
/************************************************************************/
/************************************************************************/
/* RC-signal is bad */
/* This part could be abstracted, as having yet another control input */
/* to the control mixer: An emergency autopilot control. */
/************************************************************************/
 
if(controlMixer_getSignalQuality() <= SIGNAL_BAD) { // the rc-frame signal is not reveived or noisy
RED_ON;
beepRCAlarm();
if(emergencyFlightTime) {
// continue emergency flight
emergencyFlightTime--;
if(isFlying > 256) {
// We're probably still flying. Descend slowly.
throttleTerm = staticParams.EmergencyGas; // Set emergency throttle
MKFlags |= (MKFLAG_EMERGENCY_LANDING); // Set flag for emergency landing
setStableFlightParameters();
} else {
MKFlags &= ~(MKFLAG_MOTOR_RUN); // Probably not flying, and bad R/C signal. Kill motors.
}
} else {
// end emergency flight (just cut the motors???)
MKFlags &= ~(MKFLAG_MOTOR_RUN | MKFLAG_EMERGENCY_LANDING);
}
} else {
// signal is acceptable
if(controlMixer_getSignalQuality() > SIGNAL_BAD) {
// Reset emergency landing control variables.
MKFlags &= ~(MKFLAG_EMERGENCY_LANDING); // clear flag for emergency landing
// The time is in whole seconds.
emergencyFlightTime = (uint16_t)staticParams.EmergencyGasDuration * 488;
}
if (controlMixer_getSignalQuality() <= SIGNAL_BAD) { // the rc-frame signal is not reveived or noisy
RED_ON;
beepRCAlarm();
 
// If some throttle is given, and the motor-run flag is on, increase the probability that we are flying.
if(throttleTerm > 40 && (MKFlags & MKFLAG_MOTOR_RUN)) {
// increment flight-time counter until overflow.
if(isFlying != 0xFFFF) isFlying++;
} else
/*
* When standing on the ground, do not apply I controls and zero the yaw stick.
* Probably to avoid integration effects that will cause the copter to spin
* or flip when taking off.
*/
if(isFlying < 256) {
IPart[PITCH] = IPart[ROLL] = 0;
// TODO: Don't stomp on other modules' variables!!!
// controlYaw = 0;
PDPartYaw = 0; // instead.
if(isFlying == 250) {
// HC_setGround();
updateCompassCourse = 1;
yawAngleDiff = 0;
}
} else {
// Set fly flag. TODO: Hmmm what can we trust - the isFlying counter or the flag?
// Answer: The counter. The flag is not read from anywhere anyway... except the NC maybe.
MKFlags |= (MKFLAG_FLY);
}
if (emergencyFlightTime) {
// continue emergency flight
emergencyFlightTime--;
if (isFlying > 256) {
// We're probably still flying. Descend slowly.
throttleTerm = staticParams.EmergencyGas; // Set emergency throttle
MKFlags |= (MKFLAG_EMERGENCY_LANDING); // Set flag for emergency landing
setStableFlightParameters();
} else {
MKFlags &= ~(MKFLAG_MOTOR_RUN); // Probably not flying, and bad R/C signal. Kill motors.
}
} else {
// end emergency flight (just cut the motors???)
MKFlags &= ~(MKFLAG_MOTOR_RUN | MKFLAG_EMERGENCY_LANDING);
}
} else {
// signal is acceptable
if (controlMixer_getSignalQuality() > SIGNAL_BAD) {
// Reset emergency landing control variables.
MKFlags &= ~(MKFLAG_EMERGENCY_LANDING); // clear flag for emergency landing
// The time is in whole seconds.
emergencyFlightTime = (uint16_t) staticParams.EmergencyGasDuration * 488;
}
 
commands_handleCommands();
// If some throttle is given, and the motor-run flag is on, increase the probability that we are flying.
if (throttleTerm > 40 && (MKFlags & MKFLAG_MOTOR_RUN)) {
// increment flight-time counter until overflow.
if (isFlying != 0xFFFF)
isFlying++;
} else
/*
* When standing on the ground, do not apply I controls and zero the yaw stick.
* Probably to avoid integration effects that will cause the copter to spin
* or flip when taking off.
*/
if (isFlying < 256) {
IPart[PITCH] = IPart[ROLL] = 0;
// TODO: Don't stomp on other modules' variables!!!
// controlYaw = 0;
PDPartYaw = 0; // instead.
if (isFlying == 250) {
// HC_setGround();
updateCompassCourse = 1;
yawAngleDiff = 0;
}
} else {
// Set fly flag. TODO: Hmmm what can we trust - the isFlying counter or the flag?
// Answer: The counter. The flag is not read from anywhere anyway... except the NC maybe.
MKFlags |= (MKFLAG_FLY);
}
 
// if(controlMixer_getSignalQuality() >= SIGNAL_GOOD) {
setNormalFlightParameters();
// }
} // end else (not bad signal case)
// end part1a: 750-800 usec.
/*
* Looping the H&I way basically is just a matter of turning off attitude angle measurement
* by integration (because 300 deg/s gyros are too slow) and turning down the throttle.
* This is the throttle part.
*/
if(looping) {
if(throttleTerm > staticParams.LoopGasLimit) throttleTerm = staticParams.LoopGasLimit;
}
/************************************************************************/
/* Yawing */
/************************************************************************/
if(abs(controlYaw) > 4 * staticParams.StickYawP) { // yaw stick is activated
ignoreCompassTimer = 1000;
if(!(staticParams.GlobalConfig & CFG_COMPASS_FIX)) {
updateCompassCourse = 1;
}
}
// yawControlRate = controlYaw;
commands_handleCommands();
 
// Trim drift of yawAngleDiff with controlYaw.
// TODO: We want NO feedback of control related stuff to the attitude related stuff.
// This seems to be used as: Difference desired <--> real heading.
yawAngleDiff -= controlYaw;
// limit the effect
CHECK_MIN_MAX(yawAngleDiff, -50000, 50000);
/************************************************************************/
/* Compass is currently not supported. */
/************************************************************************/
if(staticParams.GlobalConfig & (CFG_COMPASS_ACTIVE|CFG_GPS_ACTIVE)) {
updateCompass();
}
// if(controlMixer_getSignalQuality() >= SIGNAL_GOOD) {
setNormalFlightParameters();
// }
} // end else (not bad signal case)
// end part1a: 750-800 usec.
/*
* Looping the H&I way basically is just a matter of turning off attitude angle measurement
* by integration (because 300 deg/s gyros are too slow) and turning down the throttle.
* This is the throttle part.
*/
if (looping) {
if (throttleTerm > staticParams.LoopGasLimit)
throttleTerm = staticParams.LoopGasLimit;
}
 
/************************************************************************/
/* Yawing */
/************************************************************************/
if (abs(controlYaw) > 4 * staticParams.StickYawP) { // yaw stick is activated
ignoreCompassTimer = 1000;
if (!(staticParams.GlobalConfig & CFG_COMPASS_FIX)) {
updateCompassCourse = 1;
}
}
 
// yawControlRate = controlYaw;
 
// Trim drift of yawAngleDiff with controlYaw.
// TODO: We want NO feedback of control related stuff to the attitude related stuff.
// This seems to be used as: Difference desired <--> real heading.
yawAngleDiff -= controlYaw;
 
// limit the effect
CHECK_MIN_MAX(yawAngleDiff, -50000, 50000);
 
/************************************************************************/
/* Compass is currently not supported. */
/************************************************************************/
if (staticParams.GlobalConfig & (CFG_COMPASS_ACTIVE | CFG_GPS_ACTIVE)) {
updateCompass();
}
 
#if defined (USE_NAVICTRL)
/************************************************************************/
/* GPS is currently not supported. */
/************************************************************************/
if(staticParams.GlobalConfig & CFG_GPS_ACTIVE) {
GPS_Main();
MKFlags &= ~(MKFLAG_CALIBRATE | MKFLAG_START);
} else {
// GPSStickPitch = 0;
// GPSStickRoll = 0;
}
/************************************************************************/
/* GPS is currently not supported. */
/************************************************************************/
if(staticParams.GlobalConfig & CFG_GPS_ACTIVE) {
GPS_Main();
MKFlags &= ~(MKFLAG_CALIBRATE | MKFLAG_START);
} else {
// GPSStickPitch = 0;
// GPSStickRoll = 0;
}
#endif
// end part 1: 750-800 usec.
// start part 3: 350 - 400 usec.
// end part 1: 750-800 usec.
// start part 3: 350 - 400 usec.
#define SENSOR_LIMIT (4096 * 4)
/************************************************************************/
/************************************************************************/
 
/* Calculate control feedback from angle (gyro integral) */
/* and angular velocity (gyro signal) */
/************************************************************************/
// The P-part is the P of the PID controller. That's the angle integrals (not rates).
for (axis=PITCH; axis<=ROLL; axis++) {
if(looping & ((1<<4)<<axis)) {
PPart[axis] = 0;
} else { // TODO: Where do the 44000 come from???
PPart[axis] = angle[axis] * gyroIFactor / (44000 / CONTROL_SCALING); // P-Part - Proportional to Integral
}
/* Calculate control feedback from angle (gyro integral) */
/* and angular velocity (gyro signal) */
/************************************************************************/
// The P-part is the P of the PID controller. That's the angle integrals (not rates).
for (axis = PITCH; axis <= ROLL; axis++) {
if (looping & ((1 << 4) << axis)) {
PPart[axis] = 0;
} else { // TODO: Where do the 44000 come from???
PPart[axis] = angle[axis] * gyroIFactor / (44000 / CONTROL_SCALING); // P-Part - Proportional to Integral
}
 
/*
* Now blend in the D-part - proportional to the Differential of the integral = the rate.
* Read this as: PDPart = PPart + rate_PID * pfactor * CONTROL_SCALING
* where pfactor is in [0..1].
*/
PDPart[axis] = PPart[axis] + (int32_t)((int32_t)rate_PID[axis] * gyroPFactor / (256L / CONTROL_SCALING))
+ (differential[axis] * (int16_t)dynamicParams.GyroD) / 16;
/*
* Now blend in the D-part - proportional to the Differential of the integral = the rate.
* Read this as: PDPart = PPart + rate_PID * pfactor * CONTROL_SCALING
* where pfactor is in [0..1].
*/
PDPart[axis] = PPart[axis] + (int32_t) ((int32_t) rate_PID[axis]
* gyroPFactor / (256L / CONTROL_SCALING)) + (differential[axis]
* (int16_t) dynamicParams.GyroD) / 16;
 
CHECK_MIN_MAX(PDPart[axis], -SENSOR_LIMIT, SENSOR_LIMIT);
}
CHECK_MIN_MAX(PDPart[axis], -SENSOR_LIMIT, SENSOR_LIMIT);
}
 
PDPartYaw =
(int32_t)(yawRate * 2 * (int32_t)yawPFactor) / (256L / CONTROL_SCALING)
+ (int32_t)(yawAngleDiff * yawIFactor) / (2 * (44000 / CONTROL_SCALING));
// limit control feedback
CHECK_MIN_MAX(PDPartYaw, -SENSOR_LIMIT, SENSOR_LIMIT);
/*
* Compose throttle term.
* If a Bl-Ctrl is missing, prevent takeoff.
*/
if(missingMotor) {
// if we are in the lift off condition. Hmmmmmm when is throttleTerm == 0 anyway???
if(isFlying > 1 && isFlying < 50 && throttleTerm > 0)
isFlying = 1; // keep within lift off condition
throttleTerm = staticParams.MinThrottle; // reduce gas to min to avoid lift of
}
PDPartYaw = (int32_t) (yawRate * 2 * (int32_t) yawPFactor) / (256L
/ CONTROL_SCALING) + (int32_t) (yawAngleDiff * yawIFactor) / (2 * (44000
/ CONTROL_SCALING));
 
// Scale up to higher resolution. Hmm why is it not (from controlMixer and down) scaled already?
throttleTerm *= CONTROL_SCALING;
// limit control feedback
CHECK_MIN_MAX(PDPartYaw, -SENSOR_LIMIT, SENSOR_LIMIT);
 
/*
* Compose yaw term.
* The yaw term is limited: Absolute value is max. = the throttle term / 2.
* However, at low throttle the yaw term is limited to a fixed value,
* and at high throttle it is limited by the throttle reserve (the difference
* between current throttle and maximum throttle).
*/
/*
* Compose throttle term.
* If a Bl-Ctrl is missing, prevent takeoff.
*/
if (missingMotor) {
// if we are in the lift off condition. Hmmmmmm when is throttleTerm == 0 anyway???
if (isFlying > 1 && isFlying < 50 && throttleTerm > 0)
isFlying = 1; // keep within lift off condition
throttleTerm = staticParams.MinThrottle; // reduce gas to min to avoid lift of
}
 
// Scale up to higher resolution. Hmm why is it not (from controlMixer and down) scaled already?
throttleTerm *= CONTROL_SCALING;
 
/*
* Compose yaw term.
* The yaw term is limited: Absolute value is max. = the throttle term / 2.
* However, at low throttle the yaw term is limited to a fixed value,
* and at high throttle it is limited by the throttle reserve (the difference
* between current throttle and maximum throttle).
*/
#define MIN_YAWGAS (40 * CONTROL_SCALING) // yaw also below this gas value
yawTerm = PDPartYaw - controlYaw * CONTROL_SCALING;
// Limit yawTerm
if(throttleTerm > MIN_YAWGAS) {
CHECK_MIN_MAX(yawTerm, - (throttleTerm / 2), (throttleTerm / 2));
} else {
CHECK_MIN_MAX(yawTerm, - (MIN_YAWGAS / 2), (MIN_YAWGAS / 2));
}
yawTerm = PDPartYaw - controlYaw * CONTROL_SCALING;
// Limit yawTerm
if (throttleTerm > MIN_YAWGAS) {
CHECK_MIN_MAX(yawTerm, - (throttleTerm / 2), (throttleTerm / 2));
} else {
CHECK_MIN_MAX(yawTerm, - (MIN_YAWGAS / 2), (MIN_YAWGAS / 2));
}
 
tmp_int = staticParams.MaxThrottle * CONTROL_SCALING;
CHECK_MIN_MAX(yawTerm, -(tmp_int - throttleTerm), (tmp_int - throttleTerm));
tmp_int = staticParams.MaxThrottle * CONTROL_SCALING;
CHECK_MIN_MAX(yawTerm, -(tmp_int - throttleTerm), (tmp_int - throttleTerm));
 
tmp_int = (int32_t)((int32_t)dynamicParams.DynamicStability * (int32_t)(throttleTerm + abs(yawTerm) / 2)) / 64;
tmp_int = (int32_t) ((int32_t) dynamicParams.DynamicStability
* (int32_t) (throttleTerm + abs(yawTerm) / 2)) / 64;
 
for (axis=PITCH; axis<=ROLL; axis++) {
/*
* Compose pitch and roll terms. This is finally where the sticks come into play.
*/
if(gyroIFactor) {
// Integration mode: Integrate (angle - stick) = the difference between angle and stick pos.
// That means: Holding the stick a little forward will, at constant flight attitude, cause this to grow (decline??) over time.
// TODO: Find out why this seems to be proportional to stick position - not integrating it at all.
IPart[axis] += PPart[axis] - control[axis]; // Integrate difference between P part (the angle) and the stick pos.
} else {
// "HH" mode: Integrate (rate - stick) = the difference between rotation rate and stick pos.
// To keep up with a full stick PDPart should be about 156...
IPart[axis] += PDPart[axis] - control[axis]; // With gyroIFactor == 0, PDPart is really just a D-part. Integrate D-part (the rot. rate) and the stick pos.
}
for (axis = PITCH; axis <= ROLL; axis++) {
/*
* Compose pitch and roll terms. This is finally where the sticks come into play.
*/
if (gyroIFactor) {
// Integration mode: Integrate (angle - stick) = the difference between angle and stick pos.
// That means: Holding the stick a little forward will, at constant flight attitude, cause this to grow (decline??) over time.
// TODO: Find out why this seems to be proportional to stick position - not integrating it at all.
IPart[axis] += PPart[axis] - control[axis]; // Integrate difference between P part (the angle) and the stick pos.
} else {
// "HH" mode: Integrate (rate - stick) = the difference between rotation rate and stick pos.
// To keep up with a full stick PDPart should be about 156...
IPart[axis] += PDPart[axis] - control[axis]; // With gyroIFactor == 0, PDPart is really just a D-part. Integrate D-part (the rot. rate) and the stick pos.
}
 
// TODO: From which planet comes the 16000?
CHECK_MIN_MAX(IPart[axis], -(CONTROL_SCALING * 16000L), (CONTROL_SCALING * 16000L));
// Add (P, D) parts minus stick pos. to the scaled-down I part.
term[axis] = PDPart[axis] - control[axis] + IPart[axis] / Ki; // PID-controller for pitch
// TODO: From which planet comes the 16000?
CHECK_MIN_MAX(IPart[axis], -(CONTROL_SCALING * 16000L), (CONTROL_SCALING * 16000L));
// Add (P, D) parts minus stick pos. to the scaled-down I part.
term[axis] = PDPart[axis] - control[axis] + IPart[axis] / Ki; // PID-controller for pitch
 
/*
* Apply "dynamic stability" - that is: Limit pitch and roll terms to a growing function of throttle and yaw(!).
* The higher the dynamic stability parameter, the wider the bounds. 64 seems to be a kind of unity
* (max. pitch or roll term is the throttle value).
* TODO: Why a growing function of yaw?
*/
CHECK_MIN_MAX(term[axis], -tmp_int, tmp_int);
}
// end part 3: 350 - 400 usec.
/*
* Apply "dynamic stability" - that is: Limit pitch and roll terms to a growing function of throttle and yaw(!).
* The higher the dynamic stability parameter, the wider the bounds. 64 seems to be a kind of unity
* (max. pitch or roll term is the throttle value).
* TODO: Why a growing function of yaw?
*/
CHECK_MIN_MAX(term[axis], -tmp_int, tmp_int);
}
// end part 3: 350 - 400 usec.
 
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Universal Mixer
// Each (pitch, roll, throttle, yaw) term is in the range [0..255 * CONTROL_SCALING].
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Universal Mixer
// Each (pitch, roll, throttle, yaw) term is in the range [0..255 * CONTROL_SCALING].
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
DebugOut.Analog[12] = term[PITCH];
DebugOut.Analog[13] = term[ROLL];
DebugOut.Analog[14] = yawTerm;
DebugOut.Analog[15] = throttleTerm;
DebugOut.Analog[12] = term[PITCH];
DebugOut.Analog[13] = term[ROLL];
DebugOut.Analog[14] = yawTerm;
DebugOut.Analog[15] = throttleTerm;
 
for(i = 0; i < MAX_MOTORS; i++) {
int16_t tmp;
if (MKFlags & MKFLAG_MOTOR_RUN && Mixer.Motor[i][MIX_THROTTLE] > 0) {
tmp = ((int32_t)throttleTerm * Mixer.Motor[i][MIX_THROTTLE]) / 64L;
tmp += ((int32_t)term[PITCH] * Mixer.Motor[i][MIX_PITCH]) / 64L;
tmp += ((int32_t)term[ROLL] * Mixer.Motor[i][MIX_ROLL]) / 64L;
tmp += ((int32_t)yawTerm * Mixer.Motor[i][MIX_YAW]) / 64L;
motorFilters[i] = motorFilter(tmp, motorFilters[i]);
// Now we scale back down to a 0..255 range.
tmp = motorFilters[i] / CONTROL_SCALING;
// So this was the THIRD time a throttle was limited. But should the limitation
// apply to the common throttle signal (the one used for setting the "power" of
// all motors together) or should it limit the throttle set for each motor,
// including mix components of pitch, roll and yaw? I think only the common
// throttle should be limited.
// --> WRONG. This caused motors to stall completely in tight maneuvers.
// Apply to individual signals instead.
CHECK_MIN_MAX(tmp, staticParams.MinThrottle, staticParams.MaxThrottle);
CHECK_MIN_MAX(tmp, 1, 255);
motor[i].SetPoint = tmp;
}
else if (motorTestActive) {
motor[i].SetPoint = motorTest[i];
} else {
motor[i].SetPoint = 0;
}
if (i < 4)
DebugOut.Analog[22+i] = motor[i].SetPoint;
}
I2C_Start(TWI_STATE_MOTOR_TX);
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Debugging
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
if(!(--debugDataTimer)) {
debugDataTimer = 24; // update debug outputs at 488 / 24 = 20.3 Hz.
DebugOut.Analog[0] = (10 * angle[PITCH]) / GYRO_DEG_FACTOR_PITCHROLL; // in 0.1 deg
DebugOut.Analog[1] = (10 * angle[ROLL]) / GYRO_DEG_FACTOR_PITCHROLL; // in 0.1 deg
DebugOut.Analog[2] = yawGyroHeading / GYRO_DEG_FACTOR_YAW;
for (i = 0; i < MAX_MOTORS; i++) {
int16_t tmp;
if (MKFlags & MKFLAG_MOTOR_RUN && Mixer.Motor[i][MIX_THROTTLE] > 0) {
tmp = ((int32_t) throttleTerm * Mixer.Motor[i][MIX_THROTTLE]) / 64L;
tmp += ((int32_t) term[PITCH] * Mixer.Motor[i][MIX_PITCH]) / 64L;
tmp += ((int32_t) term[ROLL] * Mixer.Motor[i][MIX_ROLL]) / 64L;
tmp += ((int32_t) yawTerm * Mixer.Motor[i][MIX_YAW]) / 64L;
motorFilters[i] = motorFilter(tmp, motorFilters[i]);
// Now we scale back down to a 0..255 range.
tmp = motorFilters[i] / CONTROL_SCALING;
// So this was the THIRD time a throttle was limited. But should the limitation
// apply to the common throttle signal (the one used for setting the "power" of
// all motors together) or should it limit the throttle set for each motor,
// including mix components of pitch, roll and yaw? I think only the common
// throttle should be limited.
// --> WRONG. This caused motors to stall completely in tight maneuvers.
// Apply to individual signals instead.
CHECK_MIN_MAX(tmp, staticParams.MinThrottle, staticParams.MaxThrottle);
CHECK_MIN_MAX(tmp, 1, 255);
motor[i].SetPoint = tmp;
} else if (motorTestActive) {
motor[i].SetPoint = motorTest[i];
} else {
motor[i].SetPoint = 0;
}
if (i < 4)
DebugOut.Analog[22 + i] = motor[i].SetPoint;
}
I2C_Start(TWI_STATE_MOTOR_TX);
 
/*
DebugOut.Analog[23] = (yawRate * 2 * (int32_t)yawPFactor) / (256L / CONTROL_SCALING);
DebugOut.Analog[24] = controlYaw;
DebugOut.Analog[25] = yawAngleDiff / 100L;
DebugOut.Analog[26] = accNoisePeak[PITCH];
DebugOut.Analog[27] = accNoisePeak[ROLL];
DebugOut.Analog[30] = gyroNoisePeak[PITCH];
DebugOut.Analog[31] = gyroNoisePeak[ROLL];
*/
}
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Debugging
// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
if (!(--debugDataTimer)) {
debugDataTimer = 24; // update debug outputs at 488 / 24 = 20.3 Hz.
DebugOut.Analog[0] = (10 * angle[PITCH]) / GYRO_DEG_FACTOR_PITCHROLL; // in 0.1 deg
DebugOut.Analog[1] = (10 * angle[ROLL]) / GYRO_DEG_FACTOR_PITCHROLL; // in 0.1 deg
DebugOut.Analog[2] = yawGyroHeading / GYRO_DEG_FACTOR_YAW;
 
/*
DebugOut.Analog[23] = (yawRate * 2 * (int32_t)yawPFactor) / (256L / CONTROL_SCALING);
DebugOut.Analog[24] = controlYaw;
DebugOut.Analog[25] = yawAngleDiff / 100L;
DebugOut.Analog[26] = accNoisePeak[PITCH];
DebugOut.Analog[27] = accNoisePeak[ROLL];
DebugOut.Analog[30] = gyroNoisePeak[PITCH];
DebugOut.Analog[31] = gyroNoisePeak[ROLL];
*/
}
}
/branches/dongfang_FC_rewrite/gps.c
202,8 → 202,7
if (pTargetPos->Status != INVALID) // and the position data are valid
{
// if the target data are updated or the target pointer has changed
if ((pTargetPos->Status != PROCESSED) || (pTargetPos
!= pLastTargetPos)) {
if ((pTargetPos->Status != PROCESSED) || (pTargetPos != pLastTargetPos)) {
// reset error integral
GPSPosDevIntegral_North = 0;
GPSPosDevIntegral_East = 0;
251,8 → 250,7
// I-Part
I_North = ((int32_t) dynamicParams.NaviGpsI * GPSPosDevIntegral_North)
/ 8192;
I_East = ((int32_t) dynamicParams.NaviGpsI * GPSPosDevIntegral_East)
/ 8192;
I_East = ((int32_t) dynamicParams.NaviGpsI * GPSPosDevIntegral_East) / 8192;
 
// combine P & I
PID_North = P_North + I_North;
412,8 → 410,8
// beep if signal is not sufficient
if (!(GPSInfo.flags & FLAG_GPSFIXOK) && !(beep_rythm % 5))
BeepTime = 100;
else if (GPSInfo.satnum < staticParams.NaviGpsMinSat
&& !(beep_rythm % 5))
else if (GPSInfo.satnum < staticParams.NaviGpsMinSat && !(beep_rythm
% 5))
BeepTime = 10;
}
}
/branches/dongfang_FC_rewrite/gps.h
6,4 → 6,3
extern void GPS_Main(void);
 
#endif //_GPS_H
 
/branches/dongfang_FC_rewrite/heightControl.c
13,11 → 13,11
#define INTEGRAL_LIMIT 100000
 
/*
#define DEBUGINTEGRAL 0
#define DEBUGDIFFERENTIAL 0
#define DEBUGHOVERTHROTTLE 0
#define DEBUGHEIGHTSWITCH 0
*/
#define DEBUGINTEGRAL 0
#define DEBUGDIFFERENTIAL 0
#define DEBUGHOVERTHROTTLE 0
#define DEBUGHEIGHTSWITCH 0
*/
 
#define LATCH_TIME 40
 
36,70 → 36,70
int32_t maxHeight;
int32_t iHeight;
/*
These parameters are free to take:
uint8_t HeightMinGas; // Value : 0-100
uint8_t HeightD; // Value : 0-250
uint8_t MaxHeight; // Value : 0-32
uint8_t HeightP; // Value : 0-32
uint8_t Height_Gain; // Value : 0-50
uint8_t Height_ACC_Effect; // Value : 0-250
These parameters are free to take:
uint8_t HeightMinGas; // Value : 0-100
uint8_t HeightD; // Value : 0-250
uint8_t MaxHeight; // Value : 0-32
uint8_t HeightP; // Value : 0-32
uint8_t Height_Gain; // Value : 0-50
uint8_t Height_ACC_Effect; // Value : 0-250
*/
 
int32_t getHeight(void) {
return groundPressure - filteredAirPressure;
return groundPressure - filteredAirPressure;
}
 
void HC_setGround(void) {
groundPressure = filteredAirPressure;
// This should also happen when height control is enabled in-flight.
rampedTargetHeight = getHeight();
maxHeight = 0;
iHeight = 0;
groundPressure = filteredAirPressure;
// This should also happen when height control is enabled in-flight.
rampedTargetHeight = getHeight();
maxHeight = 0;
iHeight = 0;
}
 
void HC_update(void) {
int32_t height = getHeight();
static uint8_t setHeightLatch = 0;
int32_t height = getHeight();
static uint8_t setHeightLatch = 0;
 
if (height > maxHeight)
maxHeight = height;
if (height > maxHeight)
maxHeight = height;
 
if (staticParams.GlobalConfig & CFG_HEIGHT_SWITCH) {
// If switch is activated in config
DebugOut.Digital[0] |= DEBUG_HEIGHT_SWITCH;
if (dynamicParams.MaxHeight < 40 || dynamicParams.MaxHeight > 255-40) {
// Switch is ON
if (setHeightLatch <= LATCH_TIME) {
if (setHeightLatch == LATCH_TIME) {
// Freeze the height as target. We want to do this exactly once each time the switch is thrown ON.
targetHeight = height;
DebugOut.Digital[1] |= DEBUG_HEIGHT_SWITCH;
if (staticParams.GlobalConfig & CFG_HEIGHT_SWITCH) {
// If switch is activated in config
DebugOut.Digital[0] |= DEBUG_HEIGHT_SWITCH;
if (dynamicParams.MaxHeight < 40 || dynamicParams.MaxHeight > 255 - 40) {
// Switch is ON
if (setHeightLatch <= LATCH_TIME) {
if (setHeightLatch == LATCH_TIME) {
// Freeze the height as target. We want to do this exactly once each time the switch is thrown ON.
targetHeight = height;
DebugOut.Digital[1] |= DEBUG_HEIGHT_SWITCH;
}
// Time not yet reached.
setHeightLatch++;
}
} else {
// Switch is OFF.
setHeightLatch = 0;
DebugOut.Digital[1] &= ~DEBUG_HEIGHT_SWITCH;
}
} else {
// Switch is not activated; take the "max-height" as the target height.
DebugOut.Digital[0] &= ~DEBUG_HEIGHT_SWITCH;
targetHeight = (uint16_t) dynamicParams.MaxHeight * 100; //getHeight() + 10 * 100;
}
// Time not yet reached.
setHeightLatch++;
}
} else {
// Switch is OFF.
setHeightLatch = 0;
DebugOut.Digital[1] &= ~DEBUG_HEIGHT_SWITCH;
}
} else {
// Switch is not activated; take the "max-height" as the target height.
DebugOut.Digital[0] &= ~DEBUG_HEIGHT_SWITCH;
targetHeight = (uint16_t)dynamicParams.MaxHeight * 100; //getHeight() + 10 * 100;
}
 
if (++heightRampingTimer == INTEGRATION_FREQUENCY/10) {
heightRampingTimer = 0;
if (rampedTargetHeight + staticParams.Height_Gain <= targetHeight) {
rampedTargetHeight += staticParams.Height_Gain;
} else if (rampedTargetHeight - staticParams.Height_Gain >= targetHeight) {
rampedTargetHeight -= staticParams.Height_Gain;
}
}
// height, in meters (so the division factor is: 100)
DebugOut.Analog[30] = height / 100;
if (++heightRampingTimer == INTEGRATION_FREQUENCY / 10) {
heightRampingTimer = 0;
if (rampedTargetHeight + staticParams.Height_Gain <= targetHeight) {
rampedTargetHeight += staticParams.Height_Gain;
} else if (rampedTargetHeight - staticParams.Height_Gain >= targetHeight) {
rampedTargetHeight -= staticParams.Height_Gain;
}
}
 
// height, in meters (so the division factor is: 100)
DebugOut.Analog[30] = height / 100;
}
 
// ParamSet.GlobalConfig & CFG_HEIGHT_CONTROL
109,69 → 109,77
// takes 180-200 usec (with integral term). That is too heavy!!!
// takes 100 usec without integral term.
uint16_t HC_getThrottle(uint16_t throttle) {
int32_t height = getHeight();
int32_t heightError = rampedTargetHeight - height;
static int32_t lastHeight;
int32_t height = getHeight();
int32_t heightError = rampedTargetHeight - height;
 
int16_t dHeight = height - lastHeight;
lastHeight = height;
static int32_t lastHeight;
 
// DebugOut.Analog[20] = dHeight;
// DebugOut.Analog[21] = dynamicParams.MaxHeight;
int16_t dHeight = height - lastHeight;
lastHeight = height;
 
// iHeight, at a difference of 5 meters and a freq. of 488 Hz, will grow with 244000 / sec....
// iHeight += heightError;
// DebugOut.Analog[20] = dHeight;
// DebugOut.Analog[21] = dynamicParams.MaxHeight;
 
if (dHeight > 0) {
DebugOut.Digital[0] |= DEBUG_HEIGHT_DIFF;
DebugOut.Digital[1] &= ~DEBUG_HEIGHT_DIFF;
} else if (dHeight < 0) {
DebugOut.Digital[1] |= DEBUG_HEIGHT_DIFF;
DebugOut.Digital[0] &= ~DEBUG_HEIGHT_DIFF;
}
// iHeight, at a difference of 5 meters and a freq. of 488 Hz, will grow with 244000 / sec....
// iHeight += heightError;
 
/*
if (iHeight > INTEGRAL_LIMIT) { iHeight = INTEGRAL_LIMIT; if (DEBUGINTEGRAL) {DebugOut.Digital[0] = 1; DebugOut.Digital[1] = 1;}}
else if (iHeight < -INTEGRAL_LIMIT) { iHeight = -INTEGRAL_LIMIT; if (DEBUGINTEGRAL) {DebugOut.Digital[0] = 0; DebugOut.Digital[1] = 0; }}
else if (iHeight > 0) { if (DEBUGINTEGRAL) DebugOut.Digital[0] = 1;}
else if (iHeight < 0) { if (DEBUGINTEGRAL) DebugOut.Digital[1] = 1;}
*/
if (dHeight > 0) {
DebugOut.Digital[0] |= DEBUG_HEIGHT_DIFF;
DebugOut.Digital[1] &= ~DEBUG_HEIGHT_DIFF;
} else if (dHeight < 0) {
DebugOut.Digital[1] |= DEBUG_HEIGHT_DIFF;
DebugOut.Digital[0] &= ~DEBUG_HEIGHT_DIFF;
}
 
int16_t dThrottle = heightError * staticParams.HeightP / 1000 /*+ iHeight / 10000L * staticParams.Height_ACC_Effect */ - dHeight * staticParams.HeightD;
/*
if (iHeight > INTEGRAL_LIMIT) { iHeight = INTEGRAL_LIMIT; if (DEBUGINTEGRAL) {DebugOut.Digital[0] = 1; DebugOut.Digital[1] = 1;}}
else if (iHeight < -INTEGRAL_LIMIT) { iHeight = -INTEGRAL_LIMIT; if (DEBUGINTEGRAL) {DebugOut.Digital[0] = 0; DebugOut.Digital[1] = 0; }}
else if (iHeight > 0) { if (DEBUGINTEGRAL) DebugOut.Digital[0] = 1;}
else if (iHeight < 0) { if (DEBUGINTEGRAL) DebugOut.Digital[1] = 1;}
*/
 
// the "minGas" is now a limit for how much up / down the throttle can be varied
if (dThrottle > staticParams.HeightMinGas) dThrottle = staticParams.HeightMinGas;
else if (dThrottle < -staticParams.HeightMinGas) dThrottle = -staticParams.HeightMinGas;
int16_t dThrottle = heightError * staticParams.HeightP / 1000
/*+ iHeight / 10000L * staticParams.Height_ACC_Effect */- dHeight
* staticParams.HeightD;
 
//DebugOut.Analog[18] = dThrottle;
//DebugOut.Analog[19] = iHeight / 10000L;
// the "minGas" is now a limit for how much up / down the throttle can be varied
if (dThrottle > staticParams.HeightMinGas)
dThrottle = staticParams.HeightMinGas;
else if (dThrottle < -staticParams.HeightMinGas)
dThrottle = -staticParams.HeightMinGas;
 
// TODO: Eliminate repitition.
if (staticParams.GlobalConfig & CFG_HEIGHT_CONTROL) {
if (!(staticParams.GlobalConfig & CFG_HEIGHT_SWITCH) || (dynamicParams.MaxHeight < 40 || dynamicParams.MaxHeight > 255-40)) {
// If switch is not in use --> Just apply height control.
// If switch is in use --> only apply height control when switch is also ON.
throttle += dThrottle;
}
}
/* Experiment: Find hover-throttle */
stronglyFilteredHeightDiff = (stronglyFilteredHeightDiff * (HOVERTHROTTLEFILTER - 1) + dHeight) / HOVERTHROTTLEFILTER;
stronglyFilteredThrottle = (stronglyFilteredThrottle * (HOVERTHROTTLEFILTER - 1) + throttle) / HOVERTHROTTLEFILTER;
//DebugOut.Analog[18] = dThrottle;
//DebugOut.Analog[19] = iHeight / 10000L;
 
if (isFlying >= 1000 && stronglyFilteredHeightDiff < 3 && stronglyFilteredHeightDiff > -3) {
hoverThrottle = stronglyFilteredThrottle;
DebugOut.Digital[0] |= DEBUG_HOVERTHROTTLE;
// DebugOut.Analog[18] = hoverThrottle;
} else
DebugOut.Digital[0] &= ~DEBUG_HOVERTHROTTLE;
return throttle;
// TODO: Eliminate repitition.
if (staticParams.GlobalConfig & CFG_HEIGHT_CONTROL) {
if (!(staticParams.GlobalConfig & CFG_HEIGHT_SWITCH)
|| (dynamicParams.MaxHeight < 40 || dynamicParams.MaxHeight > 255 - 40)) {
// If switch is not in use --> Just apply height control.
// If switch is in use --> only apply height control when switch is also ON.
throttle += dThrottle;
}
}
 
/* Experiment: Find hover-throttle */
stronglyFilteredHeightDiff = (stronglyFilteredHeightDiff
* (HOVERTHROTTLEFILTER - 1) + dHeight) / HOVERTHROTTLEFILTER;
stronglyFilteredThrottle = (stronglyFilteredThrottle * (HOVERTHROTTLEFILTER
- 1) + throttle) / HOVERTHROTTLEFILTER;
 
if (isFlying >= 1000 && stronglyFilteredHeightDiff < 3
&& stronglyFilteredHeightDiff > -3) {
hoverThrottle = stronglyFilteredThrottle;
DebugOut.Digital[0] |= DEBUG_HOVERTHROTTLE;
// DebugOut.Analog[18] = hoverThrottle;
} else
DebugOut.Digital[0] &= ~DEBUG_HOVERTHROTTLE;
return throttle;
}
 
/*
For a variometer thingy:
When switch is thrown on, freeze throttle (capture it into variable)
For each iter., add (throttle - frozen throttle) to target height. Maybe don't do ramping.
Output = frozen throttle + whatever is computed +/-. Integral?
*/
For a variometer thingy:
When switch is thrown on, freeze throttle (capture it into variable)
For each iter., add (throttle - frozen throttle) to target height. Maybe don't do ramping.
Output = frozen throttle + whatever is computed +/-. Integral?
*/
/branches/dongfang_FC_rewrite/heightControl.h
1,4 → 1,3
void HC_setGround(void);
void HC_update(void);
uint16_t HC_getThrottle(uint16_t throttle);
 
void HC_setGround(void);
void HC_update(void);
uint16_t HC_getThrottle(uint16_t throttle);
/branches/dongfang_FC_rewrite/invenSense.c
8,8 → 8,8
* Configuration for my prototype board with InvenSense gyros.
* The FC 1.3 board is installed upside down, therefore Z acc is reversed but not roll.
*/
const uint8_t GYRO_REVERSED[3] = {0,0,0};
const uint8_t ACC_REVERSED[3] = {0,0,1};
const uint8_t GYRO_REVERSED[3] = { 0, 0, 0 };
const uint8_t ACC_REVERSED[3] = { 0, 0, 1 };
 
#define AUTOZERO_PORT PORTD
#define AUTOZERO_DDR DDRD
16,27 → 16,28
#define AUTOZERO_BIT 5
 
void gyro_calibrate() {
// If port not already set to output and high, do it.
if (!(AUTOZERO_DDR & (1<<AUTOZERO_BIT)) || !(AUTOZERO_PORT & (1<<AUTOZERO_BIT))) {
AUTOZERO_PORT |= (1<<AUTOZERO_BIT);
AUTOZERO_DDR |= (1<<AUTOZERO_BIT);
Delay_ms(100);
}
// Make a pulse on the auto-zero output line.
AUTOZERO_PORT &= ~(1<<AUTOZERO_BIT);
Delay_ms(1);
AUTOZERO_PORT |= (1<<AUTOZERO_BIT);
// Delay_ms(10);
Delay_ms_Mess(100);
// If port not already set to output and high, do it.
if (!(AUTOZERO_DDR & (1 << AUTOZERO_BIT)) || !(AUTOZERO_PORT & (1
<< AUTOZERO_BIT))) {
AUTOZERO_PORT |= (1 << AUTOZERO_BIT);
AUTOZERO_DDR |= (1 << AUTOZERO_BIT);
Delay_ms(100);
}
 
// Make a pulse on the auto-zero output line.
AUTOZERO_PORT &= ~(1 << AUTOZERO_BIT);
Delay_ms(1);
AUTOZERO_PORT |= (1 << AUTOZERO_BIT);
// Delay_ms(10);
Delay_ms_Mess(100);
}
 
void gyro_setDefaults(void) {
staticParams.GyroD = 3;
staticParams.GyroAccFactor = 1;
staticParams.DriftComp = 10;
staticParams.GyroD = 3;
staticParams.GyroAccFactor = 1;
staticParams.DriftComp = 10;
 
// Not used.
staticParams.AngleTurnOverPitch = 85;
staticParams.AngleTurnOverRoll = 85;
// Not used.
staticParams.AngleTurnOverPitch = 85;
staticParams.AngleTurnOverRoll = 85;
}
/branches/dongfang_FC_rewrite/invenSense.h
1,30 → 1,30
/*
#ifndef _INVENSENSE_H
#define _INVENSENSE_H
#ifndef _INVENSENSE_H
#define _INVENSENSE_H
 
#include "sensors.h"
#include "sensors.h"
 
#define GYRO_HW_NAME "ISens"
#define GYRO_HW_NAME "ISens"
/ *
/ *
* The InvenSense gyros have a lower sensitivity than for example the ADXRS610s on the FC 2.0 ME,
* but they have a wider range too.
* 2mV/deg/s gyros and no amplifiers:
* H = 0.002 V / deg / s * 1 * 1024 / 3V = 0.6827 units/(deg/s)
* /
#define GYRO_HW_FACTOR 0.6827f
#define GYRO_HW_FACTOR 0.6827f
 
/ *
/ *
* Correction factor - determined experimentally: Hold the copter in the hand, and turn it 90 degrees.
* If AnglePitch or AngleRoll in debug in MK-Tool changes by x degrees, multiply the value here by x/90.
* If the hardware related contants are set correctly, flight should be OK without bothering to
* make any adjustments here. It is only for luxury.
* /
#define GYRO_PITCHROLL_CORRECTION 0.93f
#define GYRO_PITCHROLL_CORRECTION 0.93f
 
/ *
/ *
* Same for yaw.
* /
#define GYRO_YAW_CORRECTION 0.97f
#endif
*/
#define GYRO_YAW_CORRECTION 0.97f
#endif
*/
/branches/dongfang_FC_rewrite/main.c
77,229 → 77,234
#endif
#include "eeprom.h"
 
int16_t main (void) {
uint16_t timer;
int16_t main(void) {
uint16_t timer;
 
// disable interrupts global
cli();
// disable interrupts global
cli();
 
// analyze hardware environment
CPUType = getCPUType();
BoardRelease = getBoardRelease();
// analyze hardware environment
CPUType = getCPUType();
BoardRelease = getBoardRelease();
 
// disable watchdog
MCUSR &=~(1<<WDRF);
WDTCSR |= (1<<WDCE)|(1<<WDE);
WDTCSR = 0;
// disable watchdog
MCUSR &= ~(1 << WDRF);
WDTCSR |= (1 << WDCE) | (1 << WDE);
WDTCSR = 0;
 
// PPM_in[CH_THROTTLE] = 0;
// Why??? They are already initialized to 0.
// stickPitch = stickRoll = stickYaw = 0;
// PPM_in[CH_THROTTLE] = 0;
// Why??? They are already initialized to 0.
// stickPitch = stickRoll = stickYaw = 0;
 
RED_OFF;
RED_OFF;
 
// initalize modules
output_init();
timer0_init();
timer2_init();
usart0_Init();
if(CPUType == ATMEGA644P) usart1_Init();
RC_Init();
analog_init();
I2C_init();
// initalize modules
output_init();
timer0_init();
timer2_init();
usart0_Init();
if (CPUType == ATMEGA644P)
usart1_Init();
RC_Init();
analog_init();
I2C_init();
#ifdef USE_NAVICTRL
SPI_MasterInit();
SPI_MasterInit();
#endif
#ifdef USE_MK3MAG
MK3MAG_Init();
MK3MAG_Init();
#endif
// enable interrupts global
sei();
 
printf("\n\r===================================");
printf("\n\rFlightControl");
printf("\n\rHardware: Custom");
printf("\r\n CPU: Atmega644");
if(CPUType == ATMEGA644P)
printf("p");
printf("\n\rSoftware: V%d.%d%c",VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH + 'a');
printf("\n\r===================================");
// enable interrupts global
sei();
 
// Parameter Set handling
ParamSet_Init();
printf("\n\r===================================");
printf("\n\rFlightControl");
printf("\n\rHardware: Custom");
printf("\r\n CPU: Atmega644");
if (CPUType == ATMEGA644P)
printf("p");
printf("\n\rSoftware: V%d.%d%c",VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH + 'a');
printf("\n\r===================================");
 
// Wait for a short time (otherwise the RC channel check won't work below)
// timer = SetDelay(500);
// while(!CheckDelay(timer));
// Parameter Set handling
ParamSet_Init();
 
// Instead, while away the time by flashing the 2 outputs:
// First J16, then J17. Makes it easier to see which is which.
timer = SetDelay(200);
OUTPUT_SET(0,1);
GRN_OFF;
RED_ON;
while(!CheckDelay(timer));
// Wait for a short time (otherwise the RC channel check won't work below)
// timer = SetDelay(500);
// while(!CheckDelay(timer));
 
timer = SetDelay(200);
OUTPUT_SET(0,0);
OUTPUT_SET(1,1);
RED_OFF;
GRN_ON;
while(!CheckDelay(timer));
// Instead, while away the time by flashing the 2 outputs:
// First J16, then J17. Makes it easier to see which is which.
timer = SetDelay(200);
OUTPUT_SET(0,1);
GRN_OFF;
RED_ON;
while (!CheckDelay(timer))
;
 
timer = SetDelay(200);
while(!CheckDelay(timer));
OUTPUT_SET(1,0);
timer = SetDelay(200);
OUTPUT_SET(0,0);
OUTPUT_SET(1,1);
RED_OFF;
GRN_ON;
while (!CheckDelay(timer))
;
 
twi_diagnostics();
timer = SetDelay(200);
while (!CheckDelay(timer))
;
OUTPUT_SET(1,0);
 
printf("\n\r===================================");
twi_diagnostics();
 
/*
if(staticParams.GlobalConfig & CFG_HEIGHT_CONTROL)
{
printf("\n\rCalibrating air pressure sensor..");
timer = SetDelay(1000);
SearchAirPressureOffset();
while (!CheckDelay(timer));
printf("OK\n\r");
}
*/
printf("\n\r===================================");
 
/*
if(staticParams.GlobalConfig & CFG_HEIGHT_CONTROL)
{
printf("\n\rCalibrating air pressure sensor..");
timer = SetDelay(1000);
SearchAirPressureOffset();
while (!CheckDelay(timer));
printf("OK\n\r");
}
*/
 
#ifdef USE_NAVICTRL
printf("\n\rSupport for NaviCtrl");
printf("\n\rSupport for NaviCtrl");
#ifdef USE_RC_DSL
printf("\r\nSupport for DSL RC at 2nd UART");
printf("\r\nSupport for DSL RC at 2nd UART");
#endif
#ifdef USE_RC_SPECTRUM
printf("\r\nSupport for SPECTRUM RC at 2nd UART");
printf("\r\nSupport for SPECTRUM RC at 2nd UART");
#endif
#endif
 
#ifdef USE_MK3MAG
printf("\n\rSupport for MK3MAG Compass");
printf("\n\rSupport for MK3MAG Compass");
#endif
 
#if (defined (USE_MK3MAG))
if(CPUType == ATMEGA644P) printf("\n\rSupport for GPS at 2nd UART");
else printf("\n\rSupport for GPS at 1st UART");
if(CPUType == ATMEGA644P) printf("\n\rSupport for GPS at 2nd UART");
else printf("\n\rSupport for GPS at 1st UART");
#endif
 
controlMixer_setNeutral();
controlMixer_setNeutral();
 
// Cal. attitude sensors and reset integrals.
attitude_setNeutral();
// Cal. attitude sensors and reset integrals.
attitude_setNeutral();
 
Servo_On();
Servo_On();
 
// Init flight parameters
flight_setNeutral();
// Init flight parameters
flight_setNeutral();
 
// RED_OFF;
// RED_OFF;
 
beep(2000);
printf("\n\rControl: ");
if (staticParams.GlobalConfig & CFG_HEADING_HOLD) printf("HeadingHold");
else printf("Neutral (ACC-Mode)");
beep(2000);
 
printf("\n\n\r");
printf("\n\rControl: ");
if (staticParams.GlobalConfig & CFG_HEADING_HOLD)
printf("HeadingHold");
else printf("Neutral (ACC-Mode)");
 
LCD_Clear();
printf("\n\n\r");
 
I2CTimeout = 5000;
LCD_Clear();
 
while (1) {
if(runFlightControl && analogDataReady) { // control interval
runFlightControl = 0; // reset Flag, is enabled every 2 ms by ISR of timer0
J4HIGH;
flight_control();
J4LOW;
/*
* If the motors are running (MKFlags & MKFLAG_MOTOR_RUN in flight.c), transmit
* the throttle vector just computed. Otherwise, if motor test is engaged, transmit
* the test throttle vector. If no testing, stop all motors.
*/
// Obsoleted.
// transmitMotorThrottleData();
RED_OFF;
/*
Does not belong here. Instead, external control should be ignored in
controlMixer if there was no new data from there for some time.
if(externalControlActive) externalControlActive--;
else {
externalControl.config = 0;
externalStickPitch = 0;
externalStickRoll = 0;
externalStickYaw = 0;
}
*/
/*
Does not belong here.
if(RC_Quality) RC_Quality--;
*/
/* Does not belong here. Well since we are not supporting navi right now anyway, leave out.
I2CTimeout = 5000;
 
while (1) {
if (runFlightControl && analogDataReady) { // control interval
runFlightControl = 0; // reset Flag, is enabled every 2 ms by ISR of timer0
 
J4HIGH;
flight_control();
J4LOW;
 
/*
* If the motors are running (MKFlags & MKFLAG_MOTOR_RUN in flight.c), transmit
* the throttle vector just computed. Otherwise, if motor test is engaged, transmit
* the test throttle vector. If no testing, stop all motors.
*/
// Obsoleted.
// transmitMotorThrottleData();
 
RED_OFF;
 
/*
Does not belong here. Instead, external control should be ignored in
controlMixer if there was no new data from there for some time.
if(externalControlActive) externalControlActive--;
else {
externalControl.config = 0;
externalStickPitch = 0;
externalStickRoll = 0;
externalStickYaw = 0;
}
*/
 
/*
Does not belong here.
if(RC_Quality) RC_Quality--;
*/
 
/* Does not belong here. Well since we are not supporting navi right now anyway, leave out.
#ifdef USE_NAVICTRL
if(NCDataOkay) {
if(--NCDataOkay == 0) // no data from NC
{ // set gps control sticks neutral
GPSStickPitch = 0;
GPSStickRoll = 0;
NCSerialDataOkay = 0;
}
}
#endif
*/
if (!--I2CTimeout || missingMotor) { // try to reset the i2c if motor is missing ot timeout
RED_ON;
if (!I2CTimeout) {
I2C_Reset();
I2CTimeout = 5;
}
} else {
RED_OFF;
}
 
// Allow Serial Data Transmit if motors must not updated or motors are not running
if (!runFlightControl || !(MKFlags & MKFLAG_MOTOR_RUN)) {
usart0_TransmitTxData();
}
 
usart0_ProcessRxData();
 
if (CheckDelay(timer)) {
if (UBat <= UBAT_AT_5V) {
// Do nothing. The voltage on the input side of the regulator is <5V;
// we must be running off USB power. Keep it quiet.
} else if (UBat < staticParams.LowVoltageWarning) {
beepBatteryAlarm();
}
 
#ifdef USE_NAVICTRL
if(NCDataOkay) {
if(--NCDataOkay == 0) // no data from NC
{ // set gps control sticks neutral
GPSStickPitch = 0;
GPSStickRoll = 0;
NCSerialDataOkay = 0;
}
}
SPI_StartTransmitPacket();
SendSPI = 4;
#endif
*/
if(!--I2CTimeout || missingMotor) { // try to reset the i2c if motor is missing ot timeout
RED_ON;
if(!I2CTimeout) {
I2C_Reset();
I2CTimeout = 5;
}
} else {
RED_OFF;
}
// Allow Serial Data Transmit if motors must not updated or motors are not running
if( !runFlightControl || !(MKFlags & MKFLAG_MOTOR_RUN)) {
usart0_TransmitTxData();
}
usart0_ProcessRxData();
if(CheckDelay(timer)) {
if (UBat <= UBAT_AT_5V) {
// Do nothing. The voltage on the input side of the regulator is <5V;
// we must be running off USB power. Keep it quiet.
} else if(UBat < staticParams.LowVoltageWarning) {
beepBatteryAlarm();
}
timer = SetDelay(20); // every 20 ms
}
output_update();
}
 
#ifdef USE_NAVICTRL
SPI_StartTransmitPacket();
SendSPI = 4;
if(!SendSPI) {
// SendSPI is decremented in timer0.c with a rate of 9.765 kHz.
// within the SPI_TransmitByte() routine the value is set to 4.
// I.e. the SPI_TransmitByte() is called at a rate of 9.765 kHz/4= 2441.25 Hz,
// and therefore the time of transmission of a complete spi-packet (32 bytes) is 32*4/9.765 kHz = 13.1 ms.
SPI_TransmitByte();
}
#endif
timer = SetDelay(20); // every 20 ms
}
output_update();
}
#ifdef USE_NAVICTRL
if(!SendSPI) {
// SendSPI is decremented in timer0.c with a rate of 9.765 kHz.
// within the SPI_TransmitByte() routine the value is set to 4.
// I.e. the SPI_TransmitByte() is called at a rate of 9.765 kHz/4= 2441.25 Hz,
// and therefore the time of transmission of a complete spi-packet (32 bytes) is 32*4/9.765 kHz = 13.1 ms.
SPI_TransmitByte();
}
#endif
}
return (1);
}
return (1);
}
/branches/dongfang_FC_rewrite/menu.c
81,207 → 81,217
int8_t DisplayBuff[DISPLAYBUFFSIZE] = "Hello World";
uint8_t DispPtr = 0;
 
 
/************************************/
/* Clear LCD Buffer */
/************************************/
void LCD_Clear(void) {
uint8_t i;
for( i = 0; i < DISPLAYBUFFSIZE; i++) DisplayBuff[i] = ' ';
uint8_t i;
for (i = 0; i < DISPLAYBUFFSIZE; i++)
DisplayBuff[i] = ' ';
}
 
 
/************************************/
/* Update Menu on LCD */
/************************************/
// Display with 20 characters in 4 lines
void LCD_PrintMenu(void) {
if(RemoteKeys & KEY1) {
if(MenuItem) MenuItem--;
else MenuItem = MaxMenuItem;
}
if (RemoteKeys & KEY1) {
if (MenuItem)
MenuItem--;
else
MenuItem = MaxMenuItem;
}
 
if(RemoteKeys & KEY2) {
if(MenuItem == MaxMenuItem) MenuItem = 0;
else MenuItem++;
}
if((RemoteKeys & KEY1) && (RemoteKeys & KEY2)) MenuItem = 0;
LCD_Clear();
if(MenuItem > MaxMenuItem) MenuItem = MaxMenuItem;
// print menu item number in the upper right corner
if(MenuItem < 10) {
LCD_printfxy(17,0,"[%i]",MenuItem);
} else {
LCD_printfxy(16,0,"[%i]",MenuItem);
}
switch(MenuItem) {
case 0:// Version Info Menu Item
LCD_printfxy(0,0,"+ MikroKopter +");
LCD_printfxy(0,1,"HW:V%d.%d SW:%d.%d%c",BoardRelease/10,BoardRelease%10,VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH+'a');
LCD_printfxy(0,2,"Setting: %d %s", getActiveParamSet(), Mixer.Name);
if(I2CTimeout < 6) {
LCD_printfxy(0,3,"I2C Error!!!");
} else if (missingMotor) {
LCD_printfxy(0,3,"Missing BL-Ctrl:%d", missingMotor);
}
else LCD_printfxy(0,3,"(c) Holger Buss");
break;
/*
case 1:// Height Control Menu Item
if(staticParams.GlobalConfig & CFG_HEIGHT_CONTROL) {
LCD_printfxy(0,0,"Height: %5i",ReadingHeight);
LCD_printfxy(0,1,"Set Point: %5i",SetPointHeight);
LCD_printfxy(0,2,"Air Press.:%5i",0);
LCD_printfxy(0,3,"Offset :%5i",0);
}
else
{
LCD_printfxy(0,1,"No ");
LCD_printfxy(0,2,"Height Control");
}
break;
*/
case 2:// Attitude Menu Item
LCD_printfxy(0,0,"Attitude");
LCD_printfxy(0,1,"Nick: %5i", angle[PITCH] / GYRO_DEG_FACTOR_PITCHROLL);
LCD_printfxy(0,2,"Roll: %5i", angle[ROLL ] / GYRO_DEG_FACTOR_PITCHROLL);
LCD_printfxy(0,3,"Heading: %5i", compassHeading);
break;
case 3:// Remote Control Channel Menu Item
LCD_printfxy(0,0,"C1:%4i C2:%4i ",PPM_in[1],PPM_in[2]);
LCD_printfxy(0,1,"C3:%4i C4:%4i ",PPM_in[3],PPM_in[4]);
LCD_printfxy(0,2,"C5:%4i C6:%4i ",PPM_in[5],PPM_in[6]);
LCD_printfxy(0,3,"C7:%4i C8:%4i ",PPM_in[7],PPM_in[8]);
break;
case 4:// Remote Control Mapping Menu Item
LCD_printfxy(0,0,"Ni:%4i Ro:%4i ",PPM_in[staticParams.ChannelAssignment[CH_PITCH]],PPM_in[staticParams.ChannelAssignment[CH_ROLL]]);
LCD_printfxy(0,1,"Gs:%4i Ya:%4i ",PPM_in[staticParams.ChannelAssignment[CH_THROTTLE]],PPM_in[staticParams.ChannelAssignment[CH_YAW]]);
LCD_printfxy(0,2,"P1:%4i P2:%4i ",PPM_in[staticParams.ChannelAssignment[CH_POTS]],PPM_in[staticParams.ChannelAssignment[CH_POTS+1]]);
LCD_printfxy(0,3,"P3:%4i P4:%4i ",PPM_in[staticParams.ChannelAssignment[CH_POTS+2]],PPM_in[staticParams.ChannelAssignment[CH_POTS+3]]);
break;
/*
case 5:// Gyro Sensor Menu Item
LCD_printfxy(0,0,"Gyro - Sensor");
switch(BoardRelease) {
case 10:
LCD_printfxy(0,1,"Nick %4i (%3i.%i)", AdValueGyroNick - HiResNickOffset / HIRES_GYRO_AMPLIFY, HiResNickOffset / HIRES_GYRO_AMPLIFY, HiResNickOffset % HIRES_GYRO_AMPLIFY);
LCD_printfxy(0,2,"Roll %4i (%3i.%i)", AdValueGyroRoll - HiResRollOffset / HIRES_GYRO_AMPLIFY, HiResRollOffset / HIRES_GYRO_AMPLIFY, HiResRollOffset % HIRES_GYRO_AMPLIFY);
LCD_printfxy(0,3,"Yaw %4i (%3i)", AdValueGyroYaw , YawOffset);
break;
case 11:
case 12:
case 20: // divice Offests by 2 becuse 2 samples are added in adc isr
LCD_printfxy(0,1,"Nick %4i (%3i.%i)",0, HiResNickOffset / (HIRES_GYRO_AMPLIFY * 2), (HiResNickOffset % (HIRES_GYRO_AMPLIFY * 2)) / 2); // division by 2 to push the reminder below 10 (15/2 = 7)
LCD_printfxy(0,2,"Roll %4i (%3i.%i)",0, HiResRollOffset / (HIRES_GYRO_AMPLIFY * 2), (HiResRollOffset % (HIRES_GYRO_AMPLIFY * 2)) / 2); // division by 2 to push the reminder below 10 (15/2 = 7)
LCD_printfxy(0,3,"Yaw %4i (%3i)",YawOffset - AdValueGyroYaw , YawOffset/2);
break;
case 13:
default: // divice Offests by 2 becuse 2 samples are added in adc isr
LCD_printfxy(0,1,"Nick %4i (%3i.%i)(%3i)",0, HiResNickOffset / (HIRES_GYRO_AMPLIFY * 2), (HiResNickOffset % (HIRES_GYRO_AMPLIFY * 2))/2, 0); // division by 2 to push the reminder below 10 (15/2 = 7)
LCD_printfxy(0,2,"Roll %4i (%3i.%i)(%3i)",0, HiResRollOffset / (HIRES_GYRO_AMPLIFY * 2), (HiResRollOffset % (HIRES_GYRO_AMPLIFY * 2))/2, 0); // division by 2 to push the reminder below 10 (15/2 = 7)
LCD_printfxy(0,3,"Yaw %4i (%3i)(%3i)",YawOffset - AdValueGyroYaw , YawOffset/2, 0);
break;
}
break;
case 6:// Acceleration Sensor Menu Item
LCD_printfxy(0,0,"ACC - Sensor");
LCD_printfxy(0,1,"Nick %4i (%3i)",0,0); // factor 2 because of adding 2 samples in ADC ISR
LCD_printfxy(0,2,"Roll %4i (%3i)",0,0); // factor 2 because of adding 2 samples in ADC ISR
LCD_printfxy(0,3,"Height %4i (%3i)",0,0);
break;
*/
case 7:// Battery Voltage / Remote Control Level
LCD_printfxy(0,1,"Voltage: %3i.%1iV",UBat/10, UBat%10);
LCD_printfxy(0,2,"RC-Level: %5i",RC_Quality);
break;
case 8:// Compass Menu Item
LCD_printfxy(0,0,"Compass ");
LCD_printfxy(0,1,"Course: %5i", compassCourse);
LCD_printfxy(0,2,"Heading: %5i", compassHeading);
LCD_printfxy(0,3,"OffCourse: %5i", ((540 + compassHeading - compassCourse) % 360) - 180);
break;
case 9:// Poti Menu Item
LCD_printfxy(0,0,"Po1: %3i Po5: %3i" ,variables[0], variables[4]); //PPM24-Extesion
LCD_printfxy(0,1,"Po2: %3i Po6: %3i" ,variables[1], variables[5]); //PPM24-Extesion
LCD_printfxy(0,2,"Po3: %3i Po7: %3i" ,variables[2], variables[6]); //PPM24-Extesion
LCD_printfxy(0,3,"Po4: %3i Po8: %3i" ,variables[3], variables[7]); //PPM24-Extesion
break;
/*
case 10:// Servo Menu Item
LCD_printfxy(0,0,"Servo " );
LCD_printfxy(0,1,"Setpoint %3i",dynamicParams.ServoNickControl);
LCD_printfxy(0,2,"Position: %3i",ServoNickValue);
LCD_printfxy(0,3,"Range:%3i-%3i",staticParams.ServoNickMin, staticParams.ServoNickMax);
break;
*/
case 11://Extern Control
LCD_printfxy(0,0,"ExternControl " );
LCD_printfxy(0,1,"Ni:%4i Ro:%4i ", externalControl.pitch, externalControl.roll);
LCD_printfxy(0,2,"Gs:%4i Ya:%4i ", externalControl.throttle, externalControl.yaw);
LCD_printfxy(0,3,"Hi:%4i Cf:%4i ", externalControl.height, externalControl.config);
break;
case 12://BL Communication errors
LCD_printfxy(0,0,"BL-Ctrl Errors " );
LCD_printfxy(0,1," %3d %3d %3d %3d ",motor[0].Error,motor[1].Error,motor[2].Error,motor[3].Error);
LCD_printfxy(0,2," %3d %3d %3d %3d ",motor[4].Error,motor[5].Error,motor[6].Error,motor[7].Error);
LCD_printfxy(0,3," %3d %3d %3d %3d ",motor[8].Error,motor[9].Error,motor[10].Error,motor[11].Error);
break;
case 13://BL Overview
LCD_printfxy(0,0,"BL-Ctrl found " );
LCD_printfxy(0,1," %c %c %c %c ",motor[0].Present + '-',motor[1].Present + '-',motor[2].Present + '-',motor[3].Present + '-');
LCD_printfxy(0,2," %c %c %c %c ",motor[4].Present + '-',motor[5].Present + '-',motor[6].Present + '-',motor[7].Present + '-');
LCD_printfxy(0,3," %c - - - ",motor[8].Present + '-');
if(motor[9].Present) LCD_printfxy(4,3,"10");
if(motor[10].Present) LCD_printfxy(8,3,"11");
if(motor[11].Present) LCD_printfxy(12,3,"12");
break;
if (RemoteKeys & KEY2) {
if (MenuItem == MaxMenuItem)
MenuItem = 0;
else
MenuItem++;
}
if ((RemoteKeys & KEY1) && (RemoteKeys & KEY2))
MenuItem = 0;
 
LCD_Clear();
 
if (MenuItem > MaxMenuItem)
MenuItem = MaxMenuItem;
// print menu item number in the upper right corner
if (MenuItem < 10) {
LCD_printfxy(17,0,"[%i]",MenuItem);
} else {
LCD_printfxy(16,0,"[%i]",MenuItem);
}
 
switch (MenuItem) {
case 0:// Version Info Menu Item
LCD_printfxy(0,0,"+ MikroKopter +")
;
LCD_printfxy(0,1,"HW:V%d.%d SW:%d.%d%c",BoardRelease/10,BoardRelease%10,VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH+'a')
;
LCD_printfxy(0,2,"Setting: %d %s", getActiveParamSet(), Mixer.Name)
;
if (I2CTimeout < 6) {
LCD_printfxy(0,3,"I2C Error!!!");
} else if (missingMotor) {
LCD_printfxy(0,3,"Missing BL-Ctrl:%d", missingMotor);
} else LCD_printfxy(0,3,"(c) Holger Buss");
break;
/*
case 1:// Height Control Menu Item
if(staticParams.GlobalConfig & CFG_HEIGHT_CONTROL) {
LCD_printfxy(0,0,"Height: %5i",ReadingHeight);
LCD_printfxy(0,1,"Set Point: %5i",SetPointHeight);
LCD_printfxy(0,2,"Air Press.:%5i",0);
LCD_printfxy(0,3,"Offset :%5i",0);
}
else
{
LCD_printfxy(0,1,"No ");
LCD_printfxy(0,2,"Height Control");
}
break;
*/
case 2:// Attitude Menu Item
LCD_printfxy(0,0,"Attitude");
LCD_printfxy(0,1,"Nick: %5i", angle[PITCH] / GYRO_DEG_FACTOR_PITCHROLL);
LCD_printfxy(0,2,"Roll: %5i", angle[ROLL ] / GYRO_DEG_FACTOR_PITCHROLL);
LCD_printfxy(0,3,"Heading: %5i", compassHeading);
break;
case 3:// Remote Control Channel Menu Item
LCD_printfxy(0,0,"C1:%4i C2:%4i ",PPM_in[1],PPM_in[2]);
LCD_printfxy(0,1,"C3:%4i C4:%4i ",PPM_in[3],PPM_in[4]);
LCD_printfxy(0,2,"C5:%4i C6:%4i ",PPM_in[5],PPM_in[6]);
LCD_printfxy(0,3,"C7:%4i C8:%4i ",PPM_in[7],PPM_in[8]);
break;
case 4:// Remote Control Mapping Menu Item
LCD_printfxy(0,0,"Ni:%4i Ro:%4i ",PPM_in[staticParams.ChannelAssignment[CH_PITCH]],PPM_in[staticParams.ChannelAssignment[CH_ROLL]]);
LCD_printfxy(0,1,"Gs:%4i Ya:%4i ",PPM_in[staticParams.ChannelAssignment[CH_THROTTLE]],PPM_in[staticParams.ChannelAssignment[CH_YAW]]);
LCD_printfxy(0,2,"P1:%4i P2:%4i ",PPM_in[staticParams.ChannelAssignment[CH_POTS]],PPM_in[staticParams.ChannelAssignment[CH_POTS+1]]);
LCD_printfxy(0,3,"P3:%4i P4:%4i ",PPM_in[staticParams.ChannelAssignment[CH_POTS+2]],PPM_in[staticParams.ChannelAssignment[CH_POTS+3]]);
break;
/*
case 5:// Gyro Sensor Menu Item
LCD_printfxy(0,0,"Gyro - Sensor");
switch(BoardRelease) {
case 10:
LCD_printfxy(0,1,"Nick %4i (%3i.%i)", AdValueGyroNick - HiResNickOffset / HIRES_GYRO_AMPLIFY, HiResNickOffset / HIRES_GYRO_AMPLIFY, HiResNickOffset % HIRES_GYRO_AMPLIFY);
LCD_printfxy(0,2,"Roll %4i (%3i.%i)", AdValueGyroRoll - HiResRollOffset / HIRES_GYRO_AMPLIFY, HiResRollOffset / HIRES_GYRO_AMPLIFY, HiResRollOffset % HIRES_GYRO_AMPLIFY);
LCD_printfxy(0,3,"Yaw %4i (%3i)", AdValueGyroYaw , YawOffset);
break;
case 11:
case 12:
case 20: // divice Offests by 2 becuse 2 samples are added in adc isr
LCD_printfxy(0,1,"Nick %4i (%3i.%i)",0, HiResNickOffset / (HIRES_GYRO_AMPLIFY * 2), (HiResNickOffset % (HIRES_GYRO_AMPLIFY * 2)) / 2); // division by 2 to push the reminder below 10 (15/2 = 7)
LCD_printfxy(0,2,"Roll %4i (%3i.%i)",0, HiResRollOffset / (HIRES_GYRO_AMPLIFY * 2), (HiResRollOffset % (HIRES_GYRO_AMPLIFY * 2)) / 2); // division by 2 to push the reminder below 10 (15/2 = 7)
LCD_printfxy(0,3,"Yaw %4i (%3i)",YawOffset - AdValueGyroYaw , YawOffset/2);
break;
 
case 13:
default: // divice Offests by 2 becuse 2 samples are added in adc isr
LCD_printfxy(0,1,"Nick %4i (%3i.%i)(%3i)",0, HiResNickOffset / (HIRES_GYRO_AMPLIFY * 2), (HiResNickOffset % (HIRES_GYRO_AMPLIFY * 2))/2, 0); // division by 2 to push the reminder below 10 (15/2 = 7)
LCD_printfxy(0,2,"Roll %4i (%3i.%i)(%3i)",0, HiResRollOffset / (HIRES_GYRO_AMPLIFY * 2), (HiResRollOffset % (HIRES_GYRO_AMPLIFY * 2))/2, 0); // division by 2 to push the reminder below 10 (15/2 = 7)
LCD_printfxy(0,3,"Yaw %4i (%3i)(%3i)",YawOffset - AdValueGyroYaw , YawOffset/2, 0);
break;
}
break;
case 6:// Acceleration Sensor Menu Item
LCD_printfxy(0,0,"ACC - Sensor");
LCD_printfxy(0,1,"Nick %4i (%3i)",0,0); // factor 2 because of adding 2 samples in ADC ISR
LCD_printfxy(0,2,"Roll %4i (%3i)",0,0); // factor 2 because of adding 2 samples in ADC ISR
LCD_printfxy(0,3,"Height %4i (%3i)",0,0);
break;
*/
case 7:// Battery Voltage / Remote Control Level
LCD_printfxy(0,1,"Voltage: %3i.%1iV",UBat/10, UBat%10);
LCD_printfxy(0,2,"RC-Level: %5i",RC_Quality);
break;
case 8:// Compass Menu Item
LCD_printfxy(0,0,"Compass ");
LCD_printfxy(0,1,"Course: %5i", compassCourse);
LCD_printfxy(0,2,"Heading: %5i", compassHeading);
LCD_printfxy(0,3,"OffCourse: %5i", ((540 + compassHeading - compassCourse) % 360) - 180);
break;
case 9:// Poti Menu Item
LCD_printfxy(0,0,"Po1: %3i Po5: %3i" ,variables[0], variables[4]); //PPM24-Extesion
LCD_printfxy(0,1,"Po2: %3i Po6: %3i" ,variables[1], variables[5]); //PPM24-Extesion
LCD_printfxy(0,2,"Po3: %3i Po7: %3i" ,variables[2], variables[6]); //PPM24-Extesion
LCD_printfxy(0,3,"Po4: %3i Po8: %3i" ,variables[3], variables[7]); //PPM24-Extesion
break;
/*
case 10:// Servo Menu Item
LCD_printfxy(0,0,"Servo " );
LCD_printfxy(0,1,"Setpoint %3i",dynamicParams.ServoNickControl);
LCD_printfxy(0,2,"Position: %3i",ServoNickValue);
LCD_printfxy(0,3,"Range:%3i-%3i",staticParams.ServoNickMin, staticParams.ServoNickMax);
break;
*/
case 11://Extern Control
LCD_printfxy(0,0,"ExternControl " );
LCD_printfxy(0,1,"Ni:%4i Ro:%4i ", externalControl.pitch, externalControl.roll);
LCD_printfxy(0,2,"Gs:%4i Ya:%4i ", externalControl.throttle, externalControl.yaw);
LCD_printfxy(0,3,"Hi:%4i Cf:%4i ", externalControl.height, externalControl.config);
break;
 
case 12://BL Communication errors
LCD_printfxy(0,0,"BL-Ctrl Errors " );
LCD_printfxy(0,1," %3d %3d %3d %3d ",motor[0].Error,motor[1].Error,motor[2].Error,motor[3].Error);
LCD_printfxy(0,2," %3d %3d %3d %3d ",motor[4].Error,motor[5].Error,motor[6].Error,motor[7].Error);
LCD_printfxy(0,3," %3d %3d %3d %3d ",motor[8].Error,motor[9].Error,motor[10].Error,motor[11].Error);
break;
 
case 13://BL Overview
LCD_printfxy(0,0,"BL-Ctrl found " );
LCD_printfxy(0,1," %c %c %c %c ",motor[0].Present + '-',motor[1].Present + '-',motor[2].Present + '-',motor[3].Present + '-');
LCD_printfxy(0,2," %c %c %c %c ",motor[4].Present + '-',motor[5].Present + '-',motor[6].Present + '-',motor[7].Present + '-');
LCD_printfxy(0,3," %c - - - ",motor[8].Present + '-');
if (motor[9].Present)
LCD_printfxy(4,3,"10");
if (motor[10].Present)
LCD_printfxy(8,3,"11");
if (motor[11].Present)
LCD_printfxy(12,3,"12");
break;
 
#if (defined (USE_NAVICTRL))
case 14://GPS Lat/Lon coords
if (GPSInfo.status == INVALID) {
LCD_printfxy(0,0,"No GPS data!");
} else {
switch (GPSInfo.satfix)
{
case SATFIX_NONE:
LCD_printfxy(0,0,"Sats: %d Fix: No", GPSInfo.satnum);
break;
case SATFIX_2D:
LCD_printfxy(0,0,"Sats: %d Fix: 2D", GPSInfo.satnum);
break;
case SATFIX_3D:
LCD_printfxy(0,0,"Sats: %d Fix: 3D", GPSInfo.satnum);
break;
case 14://GPS Lat/Lon coords
if (GPSInfo.status == INVALID) {
LCD_printfxy(0,0,"No GPS data!");
} else {
switch (GPSInfo.satfix)
{
case SATFIX_NONE:
LCD_printfxy(0,0,"Sats: %d Fix: No", GPSInfo.satnum);
break;
case SATFIX_2D:
LCD_printfxy(0,0,"Sats: %d Fix: 2D", GPSInfo.satnum);
break;
case SATFIX_3D:
LCD_printfxy(0,0,"Sats: %d Fix: 3D", GPSInfo.satnum);
break;
default:
LCD_printfxy(0,0,"Sats: %d Fix: ??", GPSInfo.satnum);
break;
}
int16_t i1,i2,i3;
i1 = (int16_t)(GPSInfo.longitude/10000000L);
i2 = abs((int16_t)((GPSInfo.longitude%10000000L)/10000L));
i3 = abs((int16_t)(((GPSInfo.longitude%10000000L)%10000L)/10L));
LCD_printfxy(0,1,"Lon: %d.%03d%03d deg",i1, i2, i3);
i1 = (int16_t)(GPSInfo.latitude/10000000L);
i2 = abs((int16_t)((GPSInfo.latitude%10000000L)/10000L));
i3 = abs((int16_t)(((GPSInfo.latitude%10000000L)%10000L)/10L));
LCD_printfxy(0,2,"Lat: %d.%03d%03d deg",i1, i2, i3);
i1 = (int16_t)(GPSInfo.altitude/1000L);
i2 = abs((int16_t)(GPSInfo.altitude%1000L));
LCD_printfxy(0,3,"Alt: %d.%03d m",i1, i2);
}
break;
#endif
 
default:
LCD_printfxy(0,0,"Sats: %d Fix: ??", GPSInfo.satnum);
break;
MaxMenuItem = MenuItem - 1;
MenuItem = 0;
break;
}
int16_t i1,i2,i3;
i1 = (int16_t)(GPSInfo.longitude/10000000L);
i2 = abs((int16_t)((GPSInfo.longitude%10000000L)/10000L));
i3 = abs((int16_t)(((GPSInfo.longitude%10000000L)%10000L)/10L));
LCD_printfxy(0,1,"Lon: %d.%03d%03d deg",i1, i2, i3);
i1 = (int16_t)(GPSInfo.latitude/10000000L);
i2 = abs((int16_t)((GPSInfo.latitude%10000000L)/10000L));
i3 = abs((int16_t)(((GPSInfo.latitude%10000000L)%10000L)/10L));
LCD_printfxy(0,2,"Lat: %d.%03d%03d deg",i1, i2, i3);
i1 = (int16_t)(GPSInfo.altitude/1000L);
i2 = abs((int16_t)(GPSInfo.altitude%1000L));
LCD_printfxy(0,3,"Alt: %d.%03d m",i1, i2);
}
break;
#endif
default:
MaxMenuItem = MenuItem - 1;
MenuItem = 0;
break;
}
RemoteKeys = 0;
RemoteKeys = 0;
}
/branches/dongfang_FC_rewrite/mk3mag.c
137,4 → 137,3
}
}
 
 
/branches/dongfang_FC_rewrite/mk3mag.h
2,10 → 2,10
#define _MK3MAG_H
 
typedef struct {
int16_t Attitude[2];
uint8_t UserParam[2];
uint8_t CalState;
uint8_t Orientation;
int16_t Attitude[2];
uint8_t UserParam[2];
uint8_t CalState;
uint8_t Orientation;
} ToMk3Mag_t;
 
extern ToMk3Mag_t ToMk3Mag;
17,4 → 17,3
void MK3MAG_Update(void);
 
#endif //_MK3MAG_H
 
/branches/dongfang_FC_rewrite/output.c
57,35 → 57,42
uint8_t flashCnt[2], flashMask[2];
// initializes the LED control outputs J16, J17
void output_init(void) {
// set PC2 & PC3 as output (control of J16 & J17)
DDRC |= (1<<DDC2)|(1<<DDC3);
OUTPUT_SET(0,0); OUTPUT_SET(1,0);
flashCnt[0] = flashCnt[1] = 0;
flashMask[0] = flashMask[1] = 128;
// set PC2 & PC3 as output (control of J16 & J17)
DDRC |= (1 << DDC2) | (1 << DDC3);
OUTPUT_SET(0,0);
OUTPUT_SET(1,0);
flashCnt[0] = flashCnt[1] = 0;
flashMask[0] = flashMask[1] = 128;
}
 
void flashingLight(uint8_t port, uint8_t timing, uint8_t bitmask, uint8_t manual) {
if (timing > 250 && manual > 230) {
// "timing" is set to "manual" and the value is very high --> Set to the value in bitmask bit 7.
OUTPUT_SET(port, bitmask & 128);
} else if (timing > 250 && manual < 10) {
// "timing" is set to "manual" and the value is very low --> Set to the negated value in bitmask bit 7.
OUTPUT_SET(port, !(bitmask & 128));
} else if(!flashCnt[port]--) {
// rotating mask over bitmask...
flashCnt[port] = timing - 1;
if(flashMask[port] == 1) flashMask[port] = 128; else flashMask[port] >>= 1;
OUTPUT_SET(port, flashMask[port] & bitmask);
}
void flashingLight(uint8_t port, uint8_t timing, uint8_t bitmask,
uint8_t manual) {
if (timing > 250 && manual > 230) {
// "timing" is set to "manual" and the value is very high --> Set to the value in bitmask bit 7.
OUTPUT_SET(port, bitmask & 128);
} else if (timing > 250 && manual < 10) {
// "timing" is set to "manual" and the value is very low --> Set to the negated value in bitmask bit 7.
OUTPUT_SET(port, !(bitmask & 128));
} else if (!flashCnt[port]--) {
// rotating mask over bitmask...
flashCnt[port] = timing - 1;
if (flashMask[port] == 1)
flashMask[port] = 128;
else
flashMask[port] >>= 1;
OUTPUT_SET(port, flashMask[port] & bitmask);
}
}
 
void flashingLights(void) {
static int8_t delay = 0;
if(!delay--) { // 10 ms intervals
delay = 4;
flashingLight(0, staticParams.J16Timing, staticParams.J16Bitmask, dynamicParams.J16Timing);
flashingLight(1, staticParams.J17Timing, staticParams.J17Bitmask, dynamicParams.J17Timing);
}
static int8_t delay = 0;
if (!delay--) { // 10 ms intervals
delay = 4;
flashingLight(0, staticParams.J16Timing, staticParams.J16Bitmask,
dynamicParams.J16Timing);
flashingLight(1, staticParams.J17Timing, staticParams.J17Bitmask,
dynamicParams.J17Timing);
}
}
 
/*
95,11 → 102,11
#define DIGITAL_DEBUG_MASK DEBUG_MK3MAG
 
void output_update(void) {
uint8_t output0, output1;
if (!DIGITAL_DEBUG_MASK)
flashingLights();
else {
OUTPUT_SET(0, DebugOut.Digital[0] & DIGITAL_DEBUG_MASK);
OUTPUT_SET(1, DebugOut.Digital[1] & DIGITAL_DEBUG_MASK);
}
uint8_t output0, output1;
if (!DIGITAL_DEBUG_MASK)
flashingLights();
else {
OUTPUT_SET(0, DebugOut.Digital[0] & DIGITAL_DEBUG_MASK);
OUTPUT_SET(1, DebugOut.Digital[1] & DIGITAL_DEBUG_MASK);
}
}
/branches/dongfang_FC_rewrite/rc.c
64,7 → 64,7
volatile uint8_t NewPpmData = 1;
volatile int16_t RC_Quality = 0;
int16_t RC_PRTY[4];
uint8_t lastRCCommand = COMMAND_NONE;
uint8_t lastRCCommand = COMMAND_NONE;
uint8_t commandTimer = 0;
 
// Useless. Just trim on the R/C instead.
73,54 → 73,55
/***************************************************************
* 16bit timer 1 is used to decode the PPM-Signal
***************************************************************/
void RC_Init (void) {
uint8_t sreg = SREG;
void RC_Init(void) {
uint8_t sreg = SREG;
 
// disable all interrupts before reconfiguration
cli();
// disable all interrupts before reconfiguration
cli();
 
// PPM-signal is connected to the Input Capture Pin (PD6) of timer 1
DDRD &= ~(1<<DDD6);
PORTD |= (1<<PORTD6);
// PPM-signal is connected to the Input Capture Pin (PD6) of timer 1
DDRD &= ~(1 << DDD6);
PORTD |= (1 << PORTD6);
 
// Channel 5,6,7 is decoded to servo signals at pin PD5 (J3), PD4(J4), PD3(J5)
// set as output
DDRD |= (1<<DDD5)| (1<<DDD4) | (1<<DDD3);
// low level
PORTD &= ~((1<<PORTD5) | (1<<PORTD4) | (1<<PORTD3));
// Channel 5,6,7 is decoded to servo signals at pin PD5 (J3), PD4(J4), PD3(J5)
// set as output
DDRD |= (1 << DDD5) | (1 << DDD4) | (1 << DDD3);
// low level
PORTD &= ~((1 << PORTD5) | (1 << PORTD4) | (1 << PORTD3));
 
// PD3 can't be used if 2nd UART is activated
// because TXD1 is at that port
if(CPUType != ATMEGA644P) {
DDRD |= (1<<PORTD3);
PORTD &= ~(1<<PORTD3);
}
// PD3 can't be used if 2nd UART is activated
// because TXD1 is at that port
if (CPUType != ATMEGA644P) {
DDRD |= (1 << PORTD3);
PORTD &= ~(1 << PORTD3);
}
 
// Timer/Counter1 Control Register A, B, C
// Timer/Counter1 Control Register A, B, C
 
// Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0)
// Compare output pin A & B is disabled (bits: COM1A1=0, COM1A0=0, COM1B1=0, COM1B0=0)
// Set clock source to SYSCLK/64 (bit: CS12=0, CS11=1, CS10=1)
// Enable input capture noise cancler (bit: ICNC1=1)
// Trigger on positive edge of the input capture pin (bit: ICES1=1),
// Therefore the counter incremets at a clock of 20 MHz/64 = 312.5 kHz or 3.2µs
// The longest period is 0xFFFF / 312.5 kHz = 0.209712 s.
TCCR1A &= ~((1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0)|(1<<WGM11)|(1<<WGM10));
TCCR1B &= ~((1<<WGM13)|(1<<WGM12)|(1<<CS12));
TCCR1B |= (1<<CS11)|(1<<CS10)|(1<<ICES1)|(1<<ICNC1);
TCCR1C &= ~((1<<FOC1A)|(1<<FOC1B));
// Normal Mode (bits: WGM13=0, WGM12=0, WGM11=0, WGM10=0)
// Compare output pin A & B is disabled (bits: COM1A1=0, COM1A0=0, COM1B1=0, COM1B0=0)
// Set clock source to SYSCLK/64 (bit: CS12=0, CS11=1, CS10=1)
// Enable input capture noise cancler (bit: ICNC1=1)
// Trigger on positive edge of the input capture pin (bit: ICES1=1),
// Therefore the counter incremets at a clock of 20 MHz/64 = 312.5 kHz or 3.2µs
// The longest period is 0xFFFF / 312.5 kHz = 0.209712 s.
TCCR1A &= ~((1 << COM1A1) | (1 << COM1A0) | (1 << COM1B1) | (1 << COM1B0)
| (1 << WGM11) | (1 << WGM10));
TCCR1B &= ~((1 << WGM13) | (1 << WGM12) | (1 << CS12));
TCCR1B |= (1 << CS11) | (1 << CS10) | (1 << ICES1) | (1 << ICNC1);
TCCR1C &= ~((1 << FOC1A) | (1 << FOC1B));
 
// Timer/Counter1 Interrupt Mask Register
// Timer/Counter1 Interrupt Mask Register
 
// Enable Input Capture Interrupt (bit: ICIE1=1)
// Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0)
// Enable Overflow Interrupt (bit: TOIE1=0)
TIMSK1 &= ~((1<<OCIE1B)|(1<<OCIE1A)|(1<<TOIE1));
TIMSK1 |= (1<<ICIE1);
// Enable Input Capture Interrupt (bit: ICIE1=1)
// Disable Output Compare A & B Match Interrupts (bit: OCIE1B=0, OICIE1A=0)
// Enable Overflow Interrupt (bit: TOIE1=0)
TIMSK1 &= ~((1 << OCIE1B) | (1 << OCIE1A) | (1 << TOIE1));
TIMSK1 |= (1 << ICIE1);
 
RC_Quality = 0;
RC_Quality = 0;
 
SREG = sreg;
SREG = sreg;
}
 
/********************************************************************/
127,87 → 128,90
/* Every time a positive edge is detected at PD6 */
/********************************************************************/
/* t-Frame
<----------------------------------------------------------------------->
____ ______ _____ ________ ______ sync gap ____
| | | | | | | | | | |
| | | | | | | | | | |
___| |_| |_| |_| |_.............| |________________|
<-----><-------><------><--------> <------> <---
t0 t1 t2 t4 tn t0
<----------------------------------------------------------------------->
____ ______ _____ ________ ______ sync gap ____
| | | | | | | | | | |
| | | | | | | | | | |
___| |_| |_| |_| |_.............| |________________|
<-----><-------><------><--------> <------> <---
t0 t1 t2 t4 tn t0
 
The PPM-Frame length is 22.5 ms.
Channel high pulse width range is 0.7 ms to 1.7 ms completed by an 0.3 ms low pulse.
The mininimum time delay of two events coding a channel is ( 0.7 + 0.3) ms = 1 ms.
The maximum time delay of two events coding a chanel is ( 1.7 + 0.3) ms = 2 ms.
The minimum duration of all channels at minimum value is 8 * 1 ms = 8 ms.
The maximum duration of all channels at maximum value is 8 * 2 ms = 16 ms.
The remaining time of (22.5 - 8 ms) ms = 14.5 ms to (22.5 - 16 ms) ms = 6.5 ms is
the syncronization gap.
*/
ISR(TIMER1_CAPT_vect) { // typical rate of 1 ms to 2 ms
int16_t signal = 0, tmp;
static int16_t index;
static uint16_t oldICR1 = 0;
// 16bit Input Capture Register ICR1 contains the timer value TCNT1
// at the time the edge was detected
// calculate the time delay to the previous event time which is stored in oldICR1
// calculatiing the difference of the two uint16_t and converting the result to an int16_t
// implicit handles a timer overflow 65535 -> 0 the right way.
signal = (uint16_t) ICR1 - oldICR1;
oldICR1 = ICR1;
//sync gap? (3.52 ms < signal < 25.6 ms)
if((signal > 1100) && (signal < 8000)) {
// if a sync gap happens and there where at least 4 channels decoded before
// then the NewPpmData flag is reset indicating valid data in the PPM_in[] array.
if(index >= 4) {
NewPpmData = 0; // Null means NewData for the first 4 channels
}
// synchronize channel index
index = 1;
} else { // within the PPM frame
if(index < MAX_CHANNELS-1) { // PPM24 supports 12 channels
// check for valid signal length (0.8 ms < signal < 2.1984 ms)
// signal range is from 1.0ms/3.2us = 312 to 2.0ms/3.2us = 625
if((signal > 250) && (signal < 687)) {
// shift signal to zero symmetric range -154 to 159
signal -= 470; // offset of 1.4912 ms ??? (469 * 3.2µs = 1.5008 ms)
// check for stable signal
if(abs(signal - PPM_in[index]) < 6) {
if(RC_Quality < 200) RC_Quality +=10;
else RC_Quality = 200;
The PPM-Frame length is 22.5 ms.
Channel high pulse width range is 0.7 ms to 1.7 ms completed by an 0.3 ms low pulse.
The mininimum time delay of two events coding a channel is ( 0.7 + 0.3) ms = 1 ms.
The maximum time delay of two events coding a chanel is ( 1.7 + 0.3) ms = 2 ms.
The minimum duration of all channels at minimum value is 8 * 1 ms = 8 ms.
The maximum duration of all channels at maximum value is 8 * 2 ms = 16 ms.
The remaining time of (22.5 - 8 ms) ms = 14.5 ms to (22.5 - 16 ms) ms = 6.5 ms is
the syncronization gap.
*/
ISR(TIMER1_CAPT_vect)
{ // typical rate of 1 ms to 2 ms
int16_t signal = 0, tmp;
static int16_t index;
static uint16_t oldICR1 = 0;
 
// 16bit Input Capture Register ICR1 contains the timer value TCNT1
// at the time the edge was detected
 
// calculate the time delay to the previous event time which is stored in oldICR1
// calculatiing the difference of the two uint16_t and converting the result to an int16_t
// implicit handles a timer overflow 65535 -> 0 the right way.
signal = (uint16_t) ICR1 - oldICR1;
oldICR1 = ICR1;
 
//sync gap? (3.52 ms < signal < 25.6 ms)
if ((signal > 1100) && (signal < 8000)) {
// if a sync gap happens and there where at least 4 channels decoded before
// then the NewPpmData flag is reset indicating valid data in the PPM_in[] array.
if (index >= 4) {
NewPpmData = 0; // Null means NewData for the first 4 channels
}
// synchronize channel index
index = 1;
} else { // within the PPM frame
if (index < MAX_CHANNELS - 1) { // PPM24 supports 12 channels
// check for valid signal length (0.8 ms < signal < 2.1984 ms)
// signal range is from 1.0ms/3.2us = 312 to 2.0ms/3.2us = 625
if ((signal > 250) && (signal < 687)) {
// shift signal to zero symmetric range -154 to 159
signal -= 470; // offset of 1.4912 ms ??? (469 * 3.2µs = 1.5008 ms)
// check for stable signal
if (abs(signal - PPM_in[index]) < 6) {
if (RC_Quality < 200)
RC_Quality += 10;
else
RC_Quality = 200;
}
// If signal is the same as before +/- 1, just keep it there.
if (signal >= PPM_in[index] - 1 && signal <= PPM_in[index] + 1) {
// In addition, if the signal is very close to 0, just set it to 0.
if (signal >= -1 && signal <= 1) {
tmp = 0;
} else {
tmp = PPM_in[index];
}
} else
tmp = signal;
// calculate signal difference on good signal level
if (RC_Quality >= 195)
PPM_diff[index] = ((tmp - PPM_in[index]) / 3) * 3; // cut off lower 3 bit for nois reduction
else
PPM_diff[index] = 0;
PPM_in[index] = tmp; // update channel value
}
index++; // next channel
// demux sum signal for channels 5 to 7 to J3, J4, J5
// TODO: General configurability of this R/C channel forwarding. Or remove it completely - the
// channels are usually available at the receiver anyway.
// if(index == 5) J3HIGH; else J3LOW;
// if(index == 6) J4HIGH; else J4LOW;
// if(CPUType != ATMEGA644P) // not used as TXD1
// {
// if(index == 7) J5HIGH; else J5LOW;
// }
}
}
// If signal is the same as before +/- 1, just keep it there.
if (signal>=PPM_in[index]-1 && signal<=PPM_in[index]+1) {
// In addition, if the signal is very close to 0, just set it to 0.
if (signal >=-1 && signal <= 1) {
tmp = 0;
} else {
tmp = PPM_in[index];
}
}
else
tmp = signal;
// calculate signal difference on good signal level
if(RC_Quality >= 195)
PPM_diff[index] = ((tmp - PPM_in[index]) / 3) * 3; // cut off lower 3 bit for nois reduction
else PPM_diff[index] = 0;
PPM_in[index] = tmp; // update channel value
}
index++; // next channel
// demux sum signal for channels 5 to 7 to J3, J4, J5
// TODO: General configurability of this R/C channel forwarding. Or remove it completely - the
// channels are usually available at the receiver anyway.
// if(index == 5) J3HIGH; else J3LOW;
// if(index == 6) J4HIGH; else J4LOW;
// if(CPUType != ATMEGA644P) // not used as TXD1
// {
// if(index == 7) J5HIGH; else J5LOW;
// }
}
}
}
 
#define RCChannel(dimension) PPM_in[staticParams.ChannelAssignment[dimension]]
218,23 → 222,23
 
// Internal.
uint8_t RC_getStickCommand(void) {
if(RCChannel(COMMAND_CHANNEL_VERTICAL) > COMMAND_THRESHOLD) {
// vertical is up
if(RCChannel(COMMAND_CHANNEL_HORIZONTAL) > COMMAND_THRESHOLD)
return COMMAND_GYROCAL;
if(RCChannel(COMMAND_CHANNEL_HORIZONTAL) < -COMMAND_THRESHOLD)
return COMMAND_ACCCAL;
return COMMAND_NONE;
} else if(RCChannel(COMMAND_CHANNEL_VERTICAL) < -COMMAND_THRESHOLD) {
// vertical is down
if(RCChannel(COMMAND_CHANNEL_HORIZONTAL) > COMMAND_THRESHOLD)
return COMMAND_STOP;
if(RCChannel(COMMAND_CHANNEL_HORIZONTAL) < -COMMAND_THRESHOLD)
return COMMAND_START;
return COMMAND_NONE;
}
// vertical is around center
return COMMAND_NONE;
if (RCChannel(COMMAND_CHANNEL_VERTICAL) > COMMAND_THRESHOLD) {
// vertical is up
if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) > COMMAND_THRESHOLD)
return COMMAND_GYROCAL;
if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) < -COMMAND_THRESHOLD)
return COMMAND_ACCCAL;
return COMMAND_NONE;
} else if (RCChannel(COMMAND_CHANNEL_VERTICAL) < -COMMAND_THRESHOLD) {
// vertical is down
if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) > COMMAND_THRESHOLD)
return COMMAND_STOP;
if (RCChannel(COMMAND_CHANNEL_HORIZONTAL) < -COMMAND_THRESHOLD)
return COMMAND_START;
return COMMAND_NONE;
}
// vertical is around center
return COMMAND_NONE;
}
 
/*
241,32 → 245,39
* This must be called (as the only thing) for each control loop cycle (488 Hz).
*/
void RC_update() {
int16_t tmp1, tmp2;
if(RC_Quality) {
RC_Quality--;
if (NewPpmData-- == 0) {
RC_PRTY[CONTROL_PITCH] = RCChannel(CH_PITCH) * staticParams.StickP + RCDiff(CH_PITCH) * staticParams.StickD;
RC_PRTY[CONTROL_ROLL] = RCChannel(CH_ROLL) * staticParams.StickP + RCDiff(CH_ROLL) * staticParams.StickD;
RC_PRTY[CONTROL_THROTTLE] = RCChannel(CH_THROTTLE) + RCDiff(CH_THROTTLE) * dynamicParams.UserParams[3] + 120;
if (RC_PRTY[CONTROL_THROTTLE] < 0) RC_PRTY[CONTROL_THROTTLE] = 0; // Throttle is non negative.
tmp1 = -RCChannel(CH_YAW) - RCDiff(CH_YAW);
// exponential stick sensitivity in yawing rate
tmp2 = (int32_t) staticParams.StickYawP * ((int32_t)tmp1 * abs(tmp1)) / 512L; // expo y = ax + bx^2
tmp2 += (staticParams.StickYawP * tmp1) / 4;
RC_PRTY[CONTROL_YAW] = tmp2;
}
uint8_t command = RC_getStickCommand();
if (lastRCCommand == command) {
// Keep timer from overrunning.
if (commandTimer < COMMAND_TIMER) commandTimer++;
} else {
// There was a change.
lastRCCommand = command;
commandTimer = 0;
}
} else { // Bad signal
RC_PRTY[CONTROL_PITCH] = RC_PRTY[CONTROL_ROLL] = RC_PRTY[CONTROL_THROTTLE] = RC_PRTY[CONTROL_YAW] = 0;
}
int16_t tmp1, tmp2;
if (RC_Quality) {
RC_Quality--;
if (NewPpmData-- == 0) {
RC_PRTY[CONTROL_PITCH] = RCChannel(CH_PITCH) * staticParams.StickP
+ RCDiff(CH_PITCH) * staticParams.StickD;
RC_PRTY[CONTROL_ROLL] = RCChannel(CH_ROLL) * staticParams.StickP
+ RCDiff(CH_ROLL) * staticParams.StickD;
RC_PRTY[CONTROL_THROTTLE] = RCChannel(CH_THROTTLE) + RCDiff(CH_THROTTLE)
* dynamicParams.UserParams[3] + 120;
if (RC_PRTY[CONTROL_THROTTLE] < 0)
RC_PRTY[CONTROL_THROTTLE] = 0; // Throttle is non negative.
tmp1 = -RCChannel(CH_YAW) - RCDiff(CH_YAW);
// exponential stick sensitivity in yawing rate
tmp2 = (int32_t) staticParams.StickYawP * ((int32_t) tmp1 * abs(tmp1))
/ 512L; // expo y = ax + bx^2
tmp2 += (staticParams.StickYawP * tmp1) / 4;
RC_PRTY[CONTROL_YAW] = tmp2;
}
uint8_t command = RC_getStickCommand();
if (lastRCCommand == command) {
// Keep timer from overrunning.
if (commandTimer < COMMAND_TIMER)
commandTimer++;
} else {
// There was a change.
lastRCCommand = command;
commandTimer = 0;
}
} else { // Bad signal
RC_PRTY[CONTROL_PITCH] = RC_PRTY[CONTROL_ROLL] = RC_PRTY[CONTROL_THROTTLE]
= RC_PRTY[CONTROL_YAW] = 0;
}
}
 
/*
273,35 → 284,35
* Get Pitch, Roll, Throttle, Yaw values
*/
int16_t* RC_getPRTY(void) {
return RC_PRTY;
return RC_PRTY;
}
 
/*
* Get other channel value
*/
int16_t RC_getVariable (uint8_t varNum) {
if (varNum < 4)
// 0th variable is 5th channel (1-based) etc.
return RCChannel(varNum + 4) + POT_OFFSET;
/*
* Let's just say:
* The RC variable 4 is hardwired to channel 5
* The RC variable 5 is hardwired to channel 6
* The RC variable 6 is hardwired to channel 7
* The RC variable 7 is hardwired to channel 8
* Alternatively, one could bind them to channel (4 + varNum) - or whatever...
*/
return PPM_in[varNum + 1] + POT_OFFSET;
int16_t RC_getVariable(uint8_t varNum) {
if (varNum < 4)
// 0th variable is 5th channel (1-based) etc.
return RCChannel(varNum + 4) + POT_OFFSET;
/*
* Let's just say:
* The RC variable 4 is hardwired to channel 5
* The RC variable 5 is hardwired to channel 6
* The RC variable 6 is hardwired to channel 7
* The RC variable 7 is hardwired to channel 8
* Alternatively, one could bind them to channel (4 + varNum) - or whatever...
*/
return PPM_in[varNum + 1] + POT_OFFSET;
}
 
uint8_t RC_getSignalQuality(void) {
if (RC_Quality >= 160)
return SIGNAL_GOOD;
if (RC_Quality >= 140)
return SIGNAL_OK;
if (RC_Quality >= 120)
return SIGNAL_BAD;
return SIGNAL_LOST;
if (RC_Quality >= 160)
return SIGNAL_GOOD;
if (RC_Quality >= 140)
return SIGNAL_OK;
if (RC_Quality >= 120)
return SIGNAL_BAD;
return SIGNAL_LOST;
}
 
/*
314,27 → 325,27
* of a stick, it may be useful.
*/
void RC_calibrate(void) {
// Do nothing.
// Do nothing.
}
 
/*
if (staticParams.GlobalConfig & CFG_HEADING_HOLD) {
// In HH, it s OK to trim the R/C. The effect should not be conteracted here.
stickOffsetPitch = stickOffsetRoll = 0;
} else {
stickOffsetPitch = RCChannel(CH_PITCH) * staticParams.StickP;
stickOffsetRoll = RCChannel(CH_ROLL) * staticParams.StickP;
}
}
*/
if (staticParams.GlobalConfig & CFG_HEADING_HOLD) {
// In HH, it s OK to trim the R/C. The effect should not be conteracted here.
stickOffsetPitch = stickOffsetRoll = 0;
} else {
stickOffsetPitch = RCChannel(CH_PITCH) * staticParams.StickP;
stickOffsetRoll = RCChannel(CH_ROLL) * staticParams.StickP;
}
}
*/
 
uint8_t RC_getCommand(void) {
if (commandTimer == COMMAND_TIMER) {
// Stick has been held long enough; command committed.
return lastRCCommand;
}
// Not yet sure what the command is.
return COMMAND_NONE;
if (commandTimer == COMMAND_TIMER) {
// Stick has been held long enough; command committed.
return lastRCCommand;
}
// Not yet sure what the command is.
return COMMAND_NONE;
}
 
/*
356,70 → 367,79
#define ARGUMENT_CHANNEL_HORIZONTAL CH_ROLL
 
uint8_t RC_getArgument(void) {
if(RCChannel(ARGUMENT_CHANNEL_VERTICAL) > ARGUMENT_THRESHOLD) {
// vertical is up
if(RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
return 2;
if(RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
return 4;
return 3;
} else if(RCChannel(ARGUMENT_CHANNEL_VERTICAL) < -ARGUMENT_THRESHOLD) {
// vertical is down
if(RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
return 8;
if(RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
return 6;
return 7;
} else {
// vertical is around center
if(RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
return 1;
if(RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
return 5;
return 0;
}
if (RCChannel(ARGUMENT_CHANNEL_VERTICAL) > ARGUMENT_THRESHOLD) {
// vertical is up
if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
return 2;
if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
return 4;
return 3;
} else if (RCChannel(ARGUMENT_CHANNEL_VERTICAL) < -ARGUMENT_THRESHOLD) {
// vertical is down
if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
return 8;
if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
return 6;
return 7;
} else {
// vertical is around center
if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) > ARGUMENT_THRESHOLD)
return 1;
if (RCChannel(ARGUMENT_CHANNEL_HORIZONTAL) < -ARGUMENT_THRESHOLD)
return 5;
return 0;
}
}
 
uint8_t RC_getLooping(uint8_t looping) {
// static uint8_t looping = 0;
// static uint8_t looping = 0;
 
if(RCChannel(CH_ROLL) > staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_LEFT) {
looping |= (LOOPING_ROLL_AXIS | LOOPING_LEFT);
} else if((looping & LOOPING_LEFT) && RCChannel(CH_ROLL) < staticParams.LoopThreshold - staticParams.LoopHysteresis) {
looping &= (~(LOOPING_ROLL_AXIS | LOOPING_LEFT));
}
if(RCChannel(CH_ROLL) < -staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_RIGHT) {
looping |= (LOOPING_ROLL_AXIS | LOOPING_RIGHT);
} else if((looping & LOOPING_RIGHT) && RCChannel(CH_ROLL) > -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
looping &= (~(LOOPING_ROLL_AXIS | LOOPING_RIGHT));
}
if(RCChannel(CH_PITCH) > staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_UP) {
looping |= (LOOPING_PITCH_AXIS | LOOPING_UP);
} else if((looping & LOOPING_UP) && RCChannel(CH_PITCH) < staticParams.LoopThreshold - staticParams.LoopHysteresis) {
looping &= (~(LOOPING_PITCH_AXIS | LOOPING_UP));
}
if(RCChannel(CH_PITCH) < -staticParams.LoopThreshold && staticParams.BitConfig & CFG_LOOP_DOWN) {
looping |= (LOOPING_PITCH_AXIS | LOOPING_DOWN);
} else if((looping & LOOPING_DOWN) && RCChannel(CH_PITCH) > -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
looping &= (~(LOOPING_PITCH_AXIS | LOOPING_DOWN));
}
if (RCChannel(CH_ROLL) > staticParams.LoopThreshold && staticParams.BitConfig
& CFG_LOOP_LEFT) {
looping |= (LOOPING_ROLL_AXIS | LOOPING_LEFT);
} else if ((looping & LOOPING_LEFT) && RCChannel(CH_ROLL)
< staticParams.LoopThreshold - staticParams.LoopHysteresis) {
looping &= (~(LOOPING_ROLL_AXIS | LOOPING_LEFT));
}
 
return looping;
if (RCChannel(CH_ROLL) < -staticParams.LoopThreshold
&& staticParams.BitConfig & CFG_LOOP_RIGHT) {
looping |= (LOOPING_ROLL_AXIS | LOOPING_RIGHT);
} else if ((looping & LOOPING_RIGHT) && RCChannel(CH_ROLL)
> -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
looping &= (~(LOOPING_ROLL_AXIS | LOOPING_RIGHT));
}
 
if (RCChannel(CH_PITCH) > staticParams.LoopThreshold
&& staticParams.BitConfig & CFG_LOOP_UP) {
looping |= (LOOPING_PITCH_AXIS | LOOPING_UP);
} else if ((looping & LOOPING_UP) && RCChannel(CH_PITCH)
< staticParams.LoopThreshold - staticParams.LoopHysteresis) {
looping &= (~(LOOPING_PITCH_AXIS | LOOPING_UP));
}
 
if (RCChannel(CH_PITCH) < -staticParams.LoopThreshold
&& staticParams.BitConfig & CFG_LOOP_DOWN) {
looping |= (LOOPING_PITCH_AXIS | LOOPING_DOWN);
} else if ((looping & LOOPING_DOWN) && RCChannel(CH_PITCH)
> -staticParams.LoopThreshold - staticParams.LoopHysteresis) {
looping &= (~(LOOPING_PITCH_AXIS | LOOPING_DOWN));
}
 
return looping;
}
 
uint8_t RC_testCompassCalState(void) {
static uint8_t stick = 1;
// if pitch is centered or top set stick to zero
if(RCChannel(CH_PITCH) > -20) stick = 0;
// if pitch is down trigger to next cal state
if((RCChannel(CH_PITCH) < -70) && !stick) {
stick = 1;
return 1;
}
return 0;
static uint8_t stick = 1;
// if pitch is centered or top set stick to zero
if (RCChannel(CH_PITCH) > -20)
stick = 0;
// if pitch is down trigger to next cal state
if ((RCChannel(CH_PITCH) < -70) && !stick) {
stick = 1;
return 1;
}
return 0;
}
/*
* Abstract controls are not used at the moment.
431,4 → 451,4
RC_getSignalQuality,
RC_calibrate
};
*/
*/
/branches/dongfang_FC_rewrite/rc.h
20,12 → 20,12
// Number of cycles a command must be repeated before commit.
#define COMMAND_TIMER 200
 
extern void RC_Init (void);
extern void RC_Init(void);
// the RC-Signal. todo: Not export any more.
extern volatile int16_t PPM_in[MAX_CHANNELS];
// extern volatile int16_t PPM_diff[MAX_CHANNELS]; // the differentiated RC-Signal. Should that be exported??
extern volatile uint8_t NewPpmData; // 0 indicates a new recieved PPM Frame
extern volatile int16_t RC_Quality; // rc signal quality indicator (0 to 200)
extern volatile uint8_t NewPpmData; // 0 indicates a new recieved PPM Frame
extern volatile int16_t RC_Quality; // rc signal quality indicator (0 to 200)
 
// defines for lookup staticParams.ChannelAssignment
#define CH_PITCH 0
36,20 → 36,20
#define POT_OFFSET 115
 
/*
int16_t RC_getPitch (void);
int16_t RC_getYaw (void);
int16_t RC_getRoll (void);
uint16_t RC_getThrottle (void);
uint8_t RC_hasNewRCData (void);
*/
int16_t RC_getPitch (void);
int16_t RC_getYaw (void);
int16_t RC_getRoll (void);
uint16_t RC_getThrottle (void);
uint8_t RC_hasNewRCData (void);
*/
 
void RC_update(void);
int16_t* RC_getPRTY(void);
uint8_t RC_getArgument(void);
uint8_t RC_getCommand(void);
int16_t RC_getVariable(uint8_t varNum);
void RC_calibrate(void);
uint8_t RC_getSignalQuality(void);
uint8_t RC_getLooping(uint8_t looping);
uint8_t RC_testCompassCalState(void);
void RC_update(void);
int16_t* RC_getPRTY(void);
uint8_t RC_getArgument(void);
uint8_t RC_getCommand(void);
int16_t RC_getVariable(uint8_t varNum);
void RC_calibrate(void);
uint8_t RC_getSignalQuality(void);
uint8_t RC_getLooping(uint8_t looping);
uint8_t RC_testCompassCalState(void);
#endif //_RC_H
/branches/dongfang_FC_rewrite/sod2
0,0 → 1,45
void SendOutData(uint8_t cmd, uint8_t addr, uint8_t numofbuffers, ...) { // uint8_t *pdata, uint8_t len, ...
va_list ap;
uint16_t txd_bufferIndex = 0;
uint8_t *currentBuffer;
uint8_t currentBufferIndex;
uint16_t lengthOfCurrentBuffer;
uint8_t shift = 0;
txd_buffer[txd_bufferIndex++] = '#'; // Start character
txd_buffer[txd_bufferIndex++] = 'a' + addr; // Address (a=0; b=1,...)
txd_buffer[txd_bufferIndex++] = cmd; // Command
va_start(ap, numofbuffers);
 
while(numofbuffers) {
currentBuffer = va_arg(ap, uint8_t*);
lengthOfCurrentBuffer = va_arg(ap, int);
currentBufferIndex = 0;
// Encode data: 3 bytes of data are encoded into 4 bytes,
// where the 2 most significant bits are both 0.
while(currentBufferIndex != lengthOfCurrentBuffer) {
if (!shift) txd_buffer[txd_bufferIndex] = 0;
txd_buffer[txd_bufferIndex] |= currentBuffer[currentBufferIndex] >> (shift + 2);
txd_buffer[++txd_bufferIndex] = (currentBuffer[currentBufferIndex] << (4 - shift)) & 0b00111111;
shift += 2;
if (shift == 6) { shift=0; txd_bufferIndex++; }
currentBufferIndex++;
}
}
// If the number of data bytes was not divisible by 3, stuff
// with 0 pseudodata until length is again divisible by 3.
if (shift == 2) {
// We need to stuff with zero bytes at the end.
txd_buffer[txd_bufferIndex] &= 0b00110000;
txd_buffer[++txd_bufferIndex] = 0;
shift = 4;
}
if (shift == 4) {
// We need to stuff with zero bytes at the end.
txd_buffer[txd_bufferIndex++] &= 0b00111100;
txd_buffer[txd_bufferIndex] = 0;
}
va_end(ap);
AddCRC(pt); // add checksum after data block and initates the transmission
}
/branches/dongfang_FC_rewrite/spectrum.c
1,6 → 1,6
/*#######################################################################################
Decodieren eines RC Summen Signals oder Spektrum Empfänger-Satellit
#######################################################################################*/
Decodieren eines RC Summen Signals oder Spektrum Empfänger-Satellit
#######################################################################################*/
 
#include "Spectrum.h"
 
7,58 → 7,71
//--------------------------------------------------------------//
 
//--------------------------------------------------------------//
void SpektrumBinding(void)
{
unsigned int timerTimeout = SetDelay(10000); // Timeout 10 sec.
unsigned char connected = 0;
unsigned int delaycounter;
UCSR1B &= ~(1 << RXCIE1); // disable rx-interrupt
UCSR1B &= ~(1<<RXEN1); // disable Uart-Rx
PORTD &= ~(1 << PORTD2); // disable pull-up
printf("\n\rPlease connect Spektrum receiver for binding NOW...");
while(!CheckDelay(timerTimeout))
{
if (PIND & (1 << PORTD2)) { timerTimeout = SetDelay(90); connected = 1; break; }
}
if (connected)
{
printf("ok.\n\r");
DDRD |= (1 << DDD2); // Rx as output
void SpektrumBinding(void) {
unsigned int timerTimeout = SetDelay(10000); // Timeout 10 sec.
unsigned char connected = 0;
unsigned int delaycounter;
 
while(!CheckDelay(timerTimeout)); // delay after startup of RX
for (delaycounter = 0; delaycounter < 100; delaycounter++) PORTD |= (1 << PORTD2);
for (delaycounter = 0; delaycounter < 400; delaycounter++) PORTD &= ~(1 << PORTD2);
for (delaycounter = 0; delaycounter < 10; delaycounter++) PORTD |= (1 << PORTD2);
for (delaycounter = 0; delaycounter < 10; delaycounter++) PORTD &= ~(1 << PORTD2);
for (delaycounter = 0; delaycounter < 400; delaycounter++) PORTD |= (1 << PORTD2);
for (delaycounter = 0; delaycounter < 400; delaycounter++) PORTD &= ~(1 << PORTD2);
for (delaycounter = 0; delaycounter < 10; delaycounter++) PORTD |= (1 << PORTD2);
for (delaycounter = 0; delaycounter < 10; delaycounter++) PORTD &= ~(1 << PORTD2);
for (delaycounter = 0; delaycounter < 400; delaycounter++) PORTD |= (1 << PORTD2);
for (delaycounter = 0; delaycounter < 400; delaycounter++) PORTD &= ~(1 << PORTD2);
UCSR1B &= ~(1 << RXCIE1); // disable rx-interrupt
UCSR1B &= ~(1 << RXEN1); // disable Uart-Rx
PORTD &= ~(1 << PORTD2); // disable pull-up
 
for (delaycounter = 0; delaycounter < 10; delaycounter++) PORTD |= (1 << PORTD2);
for (delaycounter = 0; delaycounter < 10; delaycounter++) PORTD &= ~(1 << PORTD2);
for (delaycounter = 0; delaycounter < 400; delaycounter++) PORTD |= (1 << PORTD2);
}
else
{ printf("Timeout.\n\r");
}
DDRD &= ~(1 << DDD2); // RX as input
PORTD &= ~(1 << PORTD2);
printf("\n\rPlease connect Spektrum receiver for binding NOW...");
 
Uart1Init(); // init Uart again
while (!CheckDelay(timerTimeout)) {
if (PIND & (1 << PORTD2)) {
timerTimeout = SetDelay(90);
connected = 1;
break;
}
}
 
if (connected) {
 
printf("ok.\n\r");
DDRD |= (1 << DDD2); // Rx as output
 
while (!CheckDelay(timerTimeout))
; // delay after startup of RX
for (delaycounter = 0; delaycounter < 100; delaycounter++)
PORTD |= (1 << PORTD2);
for (delaycounter = 0; delaycounter < 400; delaycounter++)
PORTD &= ~(1 << PORTD2);
 
for (delaycounter = 0; delaycounter < 10; delaycounter++)
PORTD |= (1 << PORTD2);
for (delaycounter = 0; delaycounter < 10; delaycounter++)
PORTD &= ~(1 << PORTD2);
for (delaycounter = 0; delaycounter < 400; delaycounter++)
PORTD |= (1 << PORTD2);
for (delaycounter = 0; delaycounter < 400; delaycounter++)
PORTD &= ~(1 << PORTD2);
 
for (delaycounter = 0; delaycounter < 10; delaycounter++)
PORTD |= (1 << PORTD2);
for (delaycounter = 0; delaycounter < 10; delaycounter++)
PORTD &= ~(1 << PORTD2);
for (delaycounter = 0; delaycounter < 400; delaycounter++)
PORTD |= (1 << PORTD2);
for (delaycounter = 0; delaycounter < 400; delaycounter++)
PORTD &= ~(1 << PORTD2);
 
for (delaycounter = 0; delaycounter < 10; delaycounter++)
PORTD |= (1 << PORTD2);
for (delaycounter = 0; delaycounter < 10; delaycounter++)
PORTD &= ~(1 << PORTD2);
for (delaycounter = 0; delaycounter < 400; delaycounter++)
PORTD |= (1 << PORTD2);
 
} else {
printf("Timeout.\n\r");
 
}
 
DDRD &= ~(1 << DDD2); // RX as input
PORTD &= ~(1 << PORTD2);
 
Uart1Init(); // init Uart again
}
 
//############################################################################
66,10 → 79,10
// USART1 initialisation from killagreg
void Uart1Init(void)
//############################################################################
{
{
// -- Start of USART1 initialisation for Spekturm seriell-mode
// USART1 Control and Status Register A, B, C and baud rate register
uint16_t ubrr = (uint16_t) ((uint32_t) SYSCLK/(8 * 115200) - 1);
uint16_t ubrr = (uint16_t) ((uint32_t) SYSCLK / (8 * 115200) - 1);
// disable RX-Interrupt
UCSR1B &= ~(1 << RXCIE1);
// disable TX-Interrupt
82,9 → 95,9
DDRD &= ~(1 << DDD2);
// USART0 Baud Rate Register
// set clock divider
UBRR1H = (uint8_t)(ubrr>>8);
UBRR1L = (uint8_t)ubrr;
 
UBRR1H = (uint8_t) (ubrr >> 8);
UBRR1L = (uint8_t) ubrr;
// enable double speed operation
UCSR1A |= (1 << U2X1);
// enable receiver and transmitter
91,9 → 104,7
//UCSR1B = (1<<RXEN1)|(1<<TXEN1);
 
 
UCSR1B = (1<<RXEN1);
UCSR1B = (1 << RXEN1);
// set asynchronous mode
UCSR1C &= ~(1 << UMSEL11);
UCSR1C &= ~(1 << UMSEL10);
104,16 → 115,17
UCSR1C &= ~(1 << USBS1);
// 8-bit
UCSR1B &= ~(1 << UCSZ12);
UCSR1C |= (1 << UCSZ11);
UCSR1C |= (1 << UCSZ10);
UCSR1C |= (1 << UCSZ11);
UCSR1C |= (1 << UCSZ10);
// flush receive buffer explicit
while(UCSR1A & (1<<RXC1)) UDR1;
while (UCSR1A & (1 << RXC1))
UDR1;
// enable RX-interrupts at the end
UCSR1B |= (1 << RXCIE1);
// -- End of USART1 initialisation
return;
}
return;
}
 
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// + Copyright (c) Rainer Walther
// + RC-routines from original MK rc.c (c) H&I
186,124 → 198,113
 
//############################################################################
//Diese Routine startet und inizialisiert den USART1 für seriellen Spektrum satellite reciever
SIGNAL(USART1_RX_vect)
SIGNAL( USART1_RX_vect)
//############################################################################
{
static unsigned int Sync=0, FrameCnt=0, ByteHigh=0, ReSync=1, Frame2=0, FrameTimer;
static unsigned int Sync = 0, FrameCnt = 0, ByteHigh = 0, ReSync = 1, Frame2 =
0, FrameTimer;
unsigned int Channel, index;
signed int signal, tmp;
int bCheckDelay;
uint8_t c;
 
c = UDR1; // get data byte
if (ReSync == 1)
{
 
if (ReSync == 1) {
// wait for beginning of new frame
ReSync = 0;
FrameTimer = SetDelay(7); // minimum 7ms zwischen den frames
 
FrameTimer = SetDelay(7); // minimum 7ms zwischen den frames
FrameCnt = 0;
Sync = 0;
ByteHigh = 0;
}
else
{
bCheckDelay = CheckDelay(FrameTimer);
if ( Sync == 0 )
{
if(bCheckDelay)
{
// nach einer Pause von mind. 7ms erstes Sync-Character gefunden
// Zeichen ignorieren, da Bedeutung unbekannt
Sync = 1;
FrameCnt ++;
} else {
bCheckDelay = CheckDelay(FrameTimer);
if (Sync == 0) {
if (bCheckDelay) {
// nach einer Pause von mind. 7ms erstes Sync-Character gefunden
// Zeichen ignorieren, da Bedeutung unbekannt
Sync = 1;
FrameCnt++;
} else {
// Zeichen kam vor Ablauf der 7ms Sync-Pause
// warten auf erstes Sync-Zeichen
}
else
{
// Zeichen kam vor Ablauf der 7ms Sync-Pause
// warten auf erstes Sync-Zeichen
} else if ((Sync == 1) && !bCheckDelay) {
// zweites Sync-Character ignorieren, Bedeutung unbekannt
Sync = 2;
FrameCnt++;
} else if ((Sync == 2) && !bCheckDelay) {
// Datenbyte high
ByteHigh = c;
 
if (FrameCnt == 2) {
// is 1st Byte of Channel-data
// Frame 1 with Channel 1-7 comming next
Frame2 = 0;
if (ByteHigh & 0x80) {
// DS9: Frame 2 with Channel 8-9 comming next
Frame2 = 1;
}
}
}
else if((Sync == 1) && !bCheckDelay)
{
// zweites Sync-Character ignorieren, Bedeutung unbekannt
Sync = 2;
FrameCnt ++;
}
else if((Sync == 2) && !bCheckDelay)
{
// Datenbyte high
ByteHigh = c;
if (FrameCnt == 2)
{
// is 1st Byte of Channel-data
// Frame 1 with Channel 1-7 comming next
Frame2 = 0;
if(ByteHigh & 0x80)
{
// DS9: Frame 2 with Channel 8-9 comming next
Frame2 = 1;
Sync = 3;
FrameCnt++;
} else if ((Sync == 3) && !bCheckDelay) {
// Datenbyte low
 
// High-Byte for next channel comes next
Sync = 2;
FrameCnt++;
 
index = (ByteHigh >> 2) & 0x0f;
index++;
Channel = (ByteHigh << 8) | c;
signal = Channel & 0x3ff;
signal -= 0x200; // Offset, range 0x000..0x3ff?
signal = signal / 3; // scaling to fit PPM resolution
 
if (index >= 0 && index <= 10) {
// Stabiles Signal
if (abs(signal - PPM_in[index]) < 6) {
if (SenderOkay < 200)
SenderOkay += 10;
else
SenderOkay = 200;
}
}
Sync = 3;
FrameCnt ++;
}
else if((Sync == 3) && !bCheckDelay)
{
// Datenbyte low
// High-Byte for next channel comes next
Sync = 2;
FrameCnt ++;
index = (ByteHigh >> 2) & 0x0f;
index ++;
Channel = (ByteHigh << 8) | c;
signal = Channel & 0x3ff;
signal -= 0x200; // Offset, range 0x000..0x3ff?
signal = signal/3; // scaling to fit PPM resolution
if(index >= 0 && index <= 10)
{
// Stabiles Signal
if(abs(signal - PPM_in[index]) < 6) { if(SenderOkay < 200) SenderOkay += 10; else SenderOkay = 200;}
tmp = (3 * (PPM_in[index]) + signal) / 4;
if(tmp > signal+1) tmp--; else
if(tmp < signal-1) tmp++;
if(SenderOkay >= 180) PPM_diff[index] = ((tmp - PPM_in[index]) / 3) * 3;
else PPM_diff[index] = 0;
PPM_in[index] = tmp;
tmp = (3 * (PPM_in[index]) + signal) / 4;
if (tmp > signal + 1)
tmp--;
else if (tmp < signal - 1)
tmp++;
if (SenderOkay >= 180)
PPM_diff[index] = ((tmp - PPM_in[index]) / 3) * 3;
else
PPM_diff[index] = 0;
PPM_in[index] = tmp;
}
} else {
// hier stimmt was nicht: neu synchronisieren
ReSync = 1;
FrameCnt = 0;
Frame2 = 0;
}
else
{
// hier stimmt was nicht: neu synchronisieren
ReSync = 1;
FrameCnt = 0;
Frame2 = 0;
}
// 16 Bytes per frame
if(FrameCnt >= 16)
{
// Frame complete
if(Frame2 == 0)
{
// Null bedeutet: Neue Daten
// nur beim ersten Frame (CH 0-7) setzen
NewPpmData = 0;
 
// 16 Bytes per frame
if (FrameCnt >= 16) {
// Frame complete
if (Frame2 == 0) {
// Null bedeutet: Neue Daten
// nur beim ersten Frame (CH 0-7) setzen
NewPpmData = 0;
}
// new frame next, nach fruehestens 7ms erwartet
FrameCnt = 0;
Frame2 = 0;
Sync = 0;
 
// new frame next, nach fruehestens 7ms erwartet
FrameCnt = 0;
Frame2 = 0;
Sync = 0;
}
// Zeit bis zum nächsten Zeichen messen
FrameTimer = SetDelay(7);
}
}
// Zeit bis zum nächsten Zeichen messen
FrameTimer = SetDelay(7);
}
}
 
 
/branches/dongfang_FC_rewrite/spectrum.h
1,6 → 1,6
/*#######################################################################################
Dekodieren eines Spectrum Signals
#######################################################################################*/
Dekodieren eines Spectrum Signals
#######################################################################################*/
 
#ifndef _SPECTRUM_H
#define _SPECTRUM_H
/branches/dongfang_FC_rewrite/spi.c
126,27 → 126,24
#define SPI_RXSYNCBYTE2 0x55
 
typedef enum {
SPI_SYNC1,
SPI_SYNC2,
SPI_DATA
SPI_SYNC1, SPI_SYNC2, SPI_DATA
} SPI_RXState_t;
 
// data exchange packets to and From NaviCtrl
ToNaviCtrl_t toNaviCtrl;
FromNaviCtrl_t fromNaviCtrl;
SPI_VersionInfo_t SPI_VersionInfo;
ToNaviCtrl_t toNaviCtrl;
FromNaviCtrl_t fromNaviCtrl;
SPI_VersionInfo_t SPI_VersionInfo;
 
 
// rx packet buffer
#define SPI_RXBUFFER_LEN sizeof(fromNaviCtrl)
uint8_t SPI_RxBuffer[SPI_RXBUFFER_LEN];
uint8_t SPI_RxBufferIndex = 0;
uint8_t SPI_RxBufferIndex = 0;
uint8_t SPI_RxBuffer_Request = 0;
 
// tx packet buffer
#define SPI_TXBUFFER_LEN sizeof(toNaviCtrl)
uint8_t *SPI_TxBuffer;
uint8_t SPI_TxBufferIndex = 0;
uint8_t SPI_TxBufferIndex = 0;
 
uint8_t SPITransferCompleted, SPI_ChkSum;
uint8_t SPI_RxDataValid = 0;
153,7 → 150,8
uint8_t NCDataOkay = 0;
uint8_t NCSerialDataOkay = 0;
 
uint8_t SPI_CommandSequence[] = { SPI_CMD_USER, SPI_CMD_STICK, SPI_CMD_PARAMETER1, SPI_CMD_STICK, SPI_CMD_MISC, SPI_CMD_VERSION };
uint8_t SPI_CommandSequence[] = { SPI_CMD_USER, SPI_CMD_STICK,
SPI_CMD_PARAMETER1, SPI_CMD_STICK, SPI_CMD_MISC, SPI_CMD_VERSION };
uint8_t SPI_CommandCounter = 0;
 
/*********************************************/
160,32 → 158,32
/* Initialize SPI interface to NaviCtrl */
/*********************************************/
void SPI_MasterInit(void) {
DDR_SPI |= (1<<DD_MOSI)|(1<<DD_SCK); // Set MOSI and SCK output, all others input
SLAVE_SELECT_DDR_PORT |= (1 << SPI_SLAVE_SELECT); // set Slave select port as output port
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(0<<SPR0)|(0<<SPIE); // Enable SPI, Master, set clock rate fck/64
SPSR = 0;//(1<<SPI2X);
SLAVE_SELECT_PORT |= (1 << SPI_SLAVE_SELECT); // Deselect Slave
SPI_TxBuffer = (uint8_t *) &toNaviCtrl; // set pointer to tx-buffer
SPITransferCompleted = 1;
// initialize data packet to NaviControl
toNaviCtrl.Sync1 = SPI_TXSYNCBYTE1;
toNaviCtrl.Sync2 = SPI_TXSYNCBYTE2;
toNaviCtrl.Command = SPI_CMD_USER;
toNaviCtrl.IntegralPitch = 0;
toNaviCtrl.IntegralRoll = 0;
NCSerialDataOkay = 0;
NCDataOkay = 0;
SPI_RxDataValid = 0;
SPI_VersionInfo.Major = VERSION_MAJOR;
SPI_VersionInfo.Minor = VERSION_MINOR;
SPI_VersionInfo.Patch = VERSION_PATCH;
SPI_VersionInfo.Compatible = NC_SPI_COMPATIBLE;
DDR_SPI |= (1 << DD_MOSI) | (1 << DD_SCK); // Set MOSI and SCK output, all others input
SLAVE_SELECT_DDR_PORT |= (1 << SPI_SLAVE_SELECT); // set Slave select port as output port
 
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (0 << SPR0) | (0 << SPIE); // Enable SPI, Master, set clock rate fck/64
SPSR = 0;//(1<<SPI2X);
 
SLAVE_SELECT_PORT |= (1 << SPI_SLAVE_SELECT); // Deselect Slave
 
SPI_TxBuffer = (uint8_t *) &toNaviCtrl; // set pointer to tx-buffer
SPITransferCompleted = 1;
// initialize data packet to NaviControl
toNaviCtrl.Sync1 = SPI_TXSYNCBYTE1;
toNaviCtrl.Sync2 = SPI_TXSYNCBYTE2;
 
toNaviCtrl.Command = SPI_CMD_USER;
toNaviCtrl.IntegralPitch = 0;
toNaviCtrl.IntegralRoll = 0;
NCSerialDataOkay = 0;
NCDataOkay = 0;
 
SPI_RxDataValid = 0;
 
SPI_VersionInfo.Major = VERSION_MAJOR;
SPI_VersionInfo.Minor = VERSION_MINOR;
SPI_VersionInfo.Patch = VERSION_PATCH;
SPI_VersionInfo.Compatible = NC_SPI_COMPATIBLE;
}
 
/**********************************************************/
192,155 → 190,203
/* Update Data transferd by the SPI from/to NaviCtrl */
/**********************************************************/
void UpdateSPI_Buffer(void) {
uint8_t i;
int16_t tmp;
cli(); // stop all interrupts to avoid writing of new data during update of that packet.
// update content of packet to NaviCtrl
toNaviCtrl.IntegralPitch = (int16_t)((10 * angle[PITCH]) / GYRO_DEG_FACTOR_PITCHROLL); // convert to multiple of 0.1°
toNaviCtrl.IntegralRoll = (int16_t)((10 * angle[ROLL]) / GYRO_DEG_FACTOR_PITCHROLL); // convert to multiple of 0.1°
toNaviCtrl.GyroHeading = (int16_t)((10 * yawGyroHeading) / GYRO_DEG_FACTOR_YAW); // convert to multiple of 0.1°
toNaviCtrl.GyroPitch = rate_ATT[PITCH];
toNaviCtrl.GyroRoll = rate_ATT[ROLL];
toNaviCtrl.GyroYaw = yawRate;
toNaviCtrl.AccPitch = (10 * getAngleEstimateFromAcc(PITCH)) / GYRO_DEG_FACTOR_PITCHROLL; // convert to multiple of 0.1°
toNaviCtrl.AccRoll = (10 * getAngleEstimateFromAcc(ROLL)) / GYRO_DEG_FACTOR_PITCHROLL; // convert to multiple of 0.1°
// TODO: What are these little bastards?
uint8_t i;
int16_t tmp;
cli();
// stop all interrupts to avoid writing of new data during update of that packet.
 
averageAcc[PITCH] = averageAcc[ROLL] = averageAccCount = 0;
switch(toNaviCtrl.Command) {
case SPI_CMD_USER:
for (i=0; i<sizeof(dynamicParams.UserParams); i++) {
toNaviCtrl.Param.Byte[i] = dynamicParams.UserParams[i];
}
toNaviCtrl.Param.Byte[8] = MKFlags;
MKFlags &= ~(MKFLAG_CALIBRATE | MKFLAG_START); // calibrate and start are temporal states that are cleared immediately after transmitting
toNaviCtrl.Param.Byte[9] = (uint8_t)UBat;
toNaviCtrl.Param.Byte[10] = staticParams.LowVoltageWarning;
toNaviCtrl.Param.Byte[11] = getActiveParamSet();
break;
// update content of packet to NaviCtrl
toNaviCtrl.IntegralPitch = (int16_t) ((10 * angle[PITCH])
/ GYRO_DEG_FACTOR_PITCHROLL); // convert to multiple of 0.1°
toNaviCtrl.IntegralRoll = (int16_t) ((10 * angle[ROLL])
/ GYRO_DEG_FACTOR_PITCHROLL); // convert to multiple of 0.1°
toNaviCtrl.GyroHeading = (int16_t) ((10 * yawGyroHeading)
/ GYRO_DEG_FACTOR_YAW); // convert to multiple of 0.1°
toNaviCtrl.GyroPitch = rate_ATT[PITCH];
toNaviCtrl.GyroRoll = rate_ATT[ROLL];
toNaviCtrl.GyroYaw = yawRate;
toNaviCtrl.AccPitch = (10 * getAngleEstimateFromAcc(PITCH))
/ GYRO_DEG_FACTOR_PITCHROLL; // convert to multiple of 0.1°
toNaviCtrl.AccRoll = (10 * getAngleEstimateFromAcc(ROLL))
/ GYRO_DEG_FACTOR_PITCHROLL; // convert to multiple of 0.1°
 
case SPI_CMD_PARAMETER1:
toNaviCtrl.Param.Byte[0] = staticParams.NaviGpsModeControl; // Parameters for the Naviboard
toNaviCtrl.Param.Byte[1] = staticParams.NaviGpsGain;
toNaviCtrl.Param.Byte[2] = staticParams.NaviGpsP;
toNaviCtrl.Param.Byte[3] = staticParams.NaviGpsI;
toNaviCtrl.Param.Byte[4] = staticParams.NaviGpsD;
toNaviCtrl.Param.Byte[5] = staticParams.NaviGpsACC;
toNaviCtrl.Param.Byte[6] = staticParams.NaviGpsMinSat;
toNaviCtrl.Param.Byte[7] = staticParams.NaviStickThreshold;
toNaviCtrl.Param.Byte[8] = staticParams.NaviOperatingRadius;
toNaviCtrl.Param.Byte[9] = staticParams.NaviWindCorrection;
toNaviCtrl.Param.Byte[10] = staticParams.NaviSpeedCompensation;
toNaviCtrl.Param.Byte[11] = staticParams.NaviAngleLimitation;
break;
case SPI_CMD_STICK:
tmp = PPM_in[staticParams.ChannelAssignment[CH_THROTTLE]]; if(tmp > 127) tmp = 127; else if(tmp < -128) tmp = -128;
toNaviCtrl.Param.Byte[0] = (int8_t) tmp;
tmp = PPM_in[staticParams.ChannelAssignment[CH_YAW]]; if(tmp > 127) tmp = 127; else if(tmp < -128) tmp = -128;
toNaviCtrl.Param.Byte[1] = (int8_t) tmp;
tmp = PPM_in[staticParams.ChannelAssignment[CH_ROLL]]; if(tmp > 127) tmp = 127; else if(tmp < -128) tmp = -128;
toNaviCtrl.Param.Byte[2] = (int8_t) tmp;
tmp = PPM_in[staticParams.ChannelAssignment[CH_PITCH]]; if(tmp > 127) tmp = 127; else if(tmp < -128) tmp = -128;
toNaviCtrl.Param.Byte[3] = (int8_t) tmp;
toNaviCtrl.Param.Byte[4] = (uint8_t) variables[0];
toNaviCtrl.Param.Byte[5] = (uint8_t) variables[1];
toNaviCtrl.Param.Byte[6] = (uint8_t) variables[2];
toNaviCtrl.Param.Byte[7] = (uint8_t) variables[3];
toNaviCtrl.Param.Byte[8] = (uint8_t) RC_Quality;
break;
 
case SPI_CMD_MISC:
toNaviCtrl.Param.Byte[0] = compassCalState;
if(compassCalState > 4) { // jump from 5 to 0
compassCalState = 0;
}
toNaviCtrl.Param.Byte[1] = staticParams.NaviPHLoginTime;
// TODO: Height and in the correct scaling...
toNaviCtrl.Param.Int[1] = 0; //readingHeight; // at address of Byte 2 and 3
toNaviCtrl.Param.Byte[4] = staticParams.NaviGpsPLimit;
toNaviCtrl.Param.Byte[5] = staticParams.NaviGpsILimit;
toNaviCtrl.Param.Byte[6] = staticParams.NaviGpsDLimit;
break;
case SPI_CMD_VERSION:
toNaviCtrl.Param.Byte[0] = SPI_VersionInfo.Major;
toNaviCtrl.Param.Byte[1] = SPI_VersionInfo.Minor;
toNaviCtrl.Param.Byte[2] = SPI_VersionInfo.Patch;
toNaviCtrl.Param.Byte[3] = SPI_VersionInfo.Compatible;
toNaviCtrl.Param.Byte[4] = BoardRelease;
break;
default:
break;
}
sei(); // enable all interrupts
// analyze content of packet from NaviCtrl if valid
if (SPI_RxDataValid) {
// update gps controls
if(abs(fromNaviCtrl.GPSStickPitch) < 512 && abs(fromNaviCtrl.GPSStickRoll) < 512 && (staticParams.GlobalConfig & CFG_GPS_ACTIVE)) {
GPSStickPitch = fromNaviCtrl.GPSStickPitch;
GPSStickRoll = fromNaviCtrl.GPSStickRoll;
NCDataOkay = 250;
}
// update compass readings
if(fromNaviCtrl.CompassHeading <= 360) {
compassHeading = fromNaviCtrl.CompassHeading;
}
//if(compassHeading < 0) compassOffCourse = 0;
//else compassOffCourse = ((540 + compassHeading - compassCourse) % 360) - 180;
// NaviCtrl wants to beep?
if (fromNaviCtrl.BeepTime > BeepTime && !compassCalState) BeepTime = fromNaviCtrl.BeepTime;
switch (fromNaviCtrl.Command) {
case SPI_KALMAN:
dynamicParams.KalmanK = fromNaviCtrl.Param.Byte[0];
dynamicParams.KalmanMaxFusion = fromNaviCtrl.Param.Byte[1];
dynamicParams.KalmanMaxDrift = fromNaviCtrl.Param.Byte[2];
NCSerialDataOkay = fromNaviCtrl.Param.Byte[3];
break;
default:
break;
}
} else { // no valid data from NaviCtrl
// disable GPS control
GPSStickPitch = 0;
GPSStickRoll = 0;
}
// TODO: What are these little bastards?
 
averageAcc[PITCH] = averageAcc[ROLL] = averageAccCount = 0;
 
switch (toNaviCtrl.Command) {
case SPI_CMD_USER:
for (i = 0; i < sizeof(dynamicParams.UserParams); i++) {
toNaviCtrl.Param.Byte[i] = dynamicParams.UserParams[i];
}
toNaviCtrl.Param.Byte[8] = MKFlags;
MKFlags &= ~(MKFLAG_CALIBRATE | MKFLAG_START); // calibrate and start are temporal states that are cleared immediately after transmitting
toNaviCtrl.Param.Byte[9] = (uint8_t) UBat;
toNaviCtrl.Param.Byte[10] = staticParams.LowVoltageWarning;
toNaviCtrl.Param.Byte[11] = getActiveParamSet();
break;
 
case SPI_CMD_PARAMETER1:
toNaviCtrl.Param.Byte[0] = staticParams.NaviGpsModeControl; // Parameters for the Naviboard
toNaviCtrl.Param.Byte[1] = staticParams.NaviGpsGain;
toNaviCtrl.Param.Byte[2] = staticParams.NaviGpsP;
toNaviCtrl.Param.Byte[3] = staticParams.NaviGpsI;
toNaviCtrl.Param.Byte[4] = staticParams.NaviGpsD;
toNaviCtrl.Param.Byte[5] = staticParams.NaviGpsACC;
toNaviCtrl.Param.Byte[6] = staticParams.NaviGpsMinSat;
toNaviCtrl.Param.Byte[7] = staticParams.NaviStickThreshold;
toNaviCtrl.Param.Byte[8] = staticParams.NaviOperatingRadius;
toNaviCtrl.Param.Byte[9] = staticParams.NaviWindCorrection;
toNaviCtrl.Param.Byte[10] = staticParams.NaviSpeedCompensation;
toNaviCtrl.Param.Byte[11] = staticParams.NaviAngleLimitation;
break;
 
case SPI_CMD_STICK:
tmp = PPM_in[staticParams.ChannelAssignment[CH_THROTTLE]];
if (tmp > 127)
tmp = 127;
else if (tmp < -128)
tmp = -128;
toNaviCtrl.Param.Byte[0] = (int8_t) tmp;
tmp = PPM_in[staticParams.ChannelAssignment[CH_YAW]];
if (tmp > 127)
tmp = 127;
else if (tmp < -128)
tmp = -128;
toNaviCtrl.Param.Byte[1] = (int8_t) tmp;
tmp = PPM_in[staticParams.ChannelAssignment[CH_ROLL]];
if (tmp > 127)
tmp = 127;
else if (tmp < -128)
tmp = -128;
toNaviCtrl.Param.Byte[2] = (int8_t) tmp;
tmp = PPM_in[staticParams.ChannelAssignment[CH_PITCH]];
if (tmp > 127)
tmp = 127;
else if (tmp < -128)
tmp = -128;
toNaviCtrl.Param.Byte[3] = (int8_t) tmp;
toNaviCtrl.Param.Byte[4] = (uint8_t) variables[0];
toNaviCtrl.Param.Byte[5] = (uint8_t) variables[1];
toNaviCtrl.Param.Byte[6] = (uint8_t) variables[2];
toNaviCtrl.Param.Byte[7] = (uint8_t) variables[3];
toNaviCtrl.Param.Byte[8] = (uint8_t) RC_Quality;
break;
 
case SPI_CMD_MISC:
toNaviCtrl.Param.Byte[0] = compassCalState;
if (compassCalState > 4) { // jump from 5 to 0
compassCalState = 0;
}
toNaviCtrl.Param.Byte[1] = staticParams.NaviPHLoginTime;
// TODO: Height and in the correct scaling...
toNaviCtrl.Param.Int[1] = 0; //readingHeight; // at address of Byte 2 and 3
toNaviCtrl.Param.Byte[4] = staticParams.NaviGpsPLimit;
toNaviCtrl.Param.Byte[5] = staticParams.NaviGpsILimit;
toNaviCtrl.Param.Byte[6] = staticParams.NaviGpsDLimit;
break;
 
case SPI_CMD_VERSION:
toNaviCtrl.Param.Byte[0] = SPI_VersionInfo.Major;
toNaviCtrl.Param.Byte[1] = SPI_VersionInfo.Minor;
toNaviCtrl.Param.Byte[2] = SPI_VersionInfo.Patch;
toNaviCtrl.Param.Byte[3] = SPI_VersionInfo.Compatible;
toNaviCtrl.Param.Byte[4] = BoardRelease;
break;
default:
break;
}
 
sei();
// enable all interrupts
 
// analyze content of packet from NaviCtrl if valid
if (SPI_RxDataValid) {
// update gps controls
if (abs(fromNaviCtrl.GPSStickPitch) < 512 && abs(fromNaviCtrl.GPSStickRoll)
< 512 && (staticParams.GlobalConfig & CFG_GPS_ACTIVE)) {
GPSStickPitch = fromNaviCtrl.GPSStickPitch;
GPSStickRoll = fromNaviCtrl.GPSStickRoll;
NCDataOkay = 250;
}
// update compass readings
if (fromNaviCtrl.CompassHeading <= 360) {
compassHeading = fromNaviCtrl.CompassHeading;
}
//if(compassHeading < 0) compassOffCourse = 0;
//else compassOffCourse = ((540 + compassHeading - compassCourse) % 360) - 180;
// NaviCtrl wants to beep?
if (fromNaviCtrl.BeepTime > BeepTime && !compassCalState)
BeepTime = fromNaviCtrl.BeepTime;
 
switch (fromNaviCtrl.Command) {
case SPI_KALMAN:
dynamicParams.KalmanK = fromNaviCtrl.Param.Byte[0];
dynamicParams.KalmanMaxFusion = fromNaviCtrl.Param.Byte[1];
dynamicParams.KalmanMaxDrift = fromNaviCtrl.Param.Byte[2];
NCSerialDataOkay = fromNaviCtrl.Param.Byte[3];
break;
 
default:
break;
}
} else { // no valid data from NaviCtrl
// disable GPS control
GPSStickPitch = 0;
GPSStickRoll = 0;
}
}
 
/*********************************************/
/* Start Transmission of packet to NaviCtrl */
/*********************************************/
void SPI_StartTransmitPacket(void){
if (!SPITransferCompleted) return; // return immediately if transfer is in progress
else // transmission was completed
{
SLAVE_SELECT_PORT &= ~(1 << SPI_SLAVE_SELECT); // Select slave
// cyclic commands
toNaviCtrl.Command = SPI_CommandSequence[SPI_CommandCounter++];
if (SPI_CommandCounter >= sizeof(SPI_CommandSequence)) SPI_CommandCounter = 0;
SPITransferCompleted = 0; // transfer is in progress
UpdateSPI_Buffer(); // update data in toNaviCtrl
SPI_TxBufferIndex = 1; //proceed with 2nd byte
// -- Debug-Output ---
//----
asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop");
asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop");
asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop");
toNaviCtrl.Chksum = toNaviCtrl.Sync1; // init checksum
SPDR = toNaviCtrl.Sync1; // send first byte
}
void SPI_StartTransmitPacket(void) {
if (!SPITransferCompleted)
return; // return immediately if transfer is in progress
else // transmission was completed
{
SLAVE_SELECT_PORT &= ~(1 << SPI_SLAVE_SELECT); // Select slave
 
// cyclic commands
toNaviCtrl.Command = SPI_CommandSequence[SPI_CommandCounter++];
if (SPI_CommandCounter >= sizeof(SPI_CommandSequence))
SPI_CommandCounter = 0;
 
SPITransferCompleted = 0; // transfer is in progress
UpdateSPI_Buffer(); // update data in toNaviCtrl
 
SPI_TxBufferIndex = 1; //proceed with 2nd byte
 
// -- Debug-Output ---
//----
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
toNaviCtrl.Chksum = toNaviCtrl.Sync1; // init checksum
SPDR = toNaviCtrl.Sync1; // send first byte
}
}
 
//------------------------------------------------------
349,73 → 395,93
// the NaviCtrl and one byte of the packet from the NaviCtrl is possible transfered
 
void SPI_TransmitByte(void) {
static SPI_RXState_t SPI_RXState = SPI_SYNC1;
uint8_t rxdata;
static uint8_t rxchksum;
if (SPITransferCompleted) return; // return immediatly if transfer was completed
if (!(SPSR & (1 << SPIF))) return; // return if no SPI-IRQ pending
SendSPI = 4; // mait 4 * 0.102 ms for the next call of SPI_TransmitByte() in the main loop
SLAVE_SELECT_PORT |= (1 << SPI_SLAVE_SELECT); // DeselectSlave
rxdata = SPDR; // save spi data register
switch (SPI_RXState) {
case SPI_SYNC1: // first sync byte
SPI_RxBufferIndex = 0; // set pointer to start of rx buffer
rxchksum = rxdata; // initialize checksum
if (rxdata == SPI_RXSYNCBYTE1 )
{ // 1st Syncbyte found
SPI_RXState = SPI_SYNC2; // trigger to state for second sync byte
}
break;
case SPI_SYNC2: // second sync byte
if (rxdata == SPI_RXSYNCBYTE2)
{ // 2nd Syncbyte found
rxchksum += rxdata; // update checksum
SPI_RXState = SPI_DATA; // trigger to state for second sync byte
}
else // 2nd Syncbyte not found
{
SPI_RXState = SPI_SYNC1; // jump back to 1st sync byte
}
break;
case SPI_DATA: // data bytes
SPI_RxBuffer[SPI_RxBufferIndex++] = rxdata; // copy data byte to spi buffer
// if all bytes are received of a packet from the NaviCtrl
if (SPI_RxBufferIndex >= SPI_RXBUFFER_LEN) { // last byte transfered is the checksum of the packet
if (rxdata == rxchksum) { // checksum matching?
// copy SPI_RxBuffer -> FromFlightCtrl
uint8_t *ptr = (uint8_t *)&fromNaviCtrl;
cli();
memcpy(ptr, (uint8_t *) SPI_RxBuffer, sizeof(fromNaviCtrl));
sei();
SPI_RxDataValid = 1;
} else { // checksum does not match
SPI_RxDataValid = 0; // reset valid flag
}
SPI_RXState = SPI_SYNC1; // reset state sync
} else { // not all bytes transfered
rxchksum += rxdata; // update checksum
}
break;
}// eof switch(SPI_RXState)
// if still some bytes left for transmission to NaviCtrl
if (SPI_TxBufferIndex < SPI_TXBUFFER_LEN) {
SLAVE_SELECT_PORT &= ~(1 << SPI_SLAVE_SELECT); // SelectSlave
asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop");
asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop");
asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop"); asm volatile ("nop");
SPDR = SPI_TxBuffer[SPI_TxBufferIndex]; // transmit byte
toNaviCtrl.Chksum += SPI_TxBuffer[SPI_TxBufferIndex]; // update checksum for everey byte that was sent
SPI_TxBufferIndex++;
} else {
//Transfer of all bytes of the packet to NaviCtrl completed
SPITransferCompleted = 1;
}
static SPI_RXState_t SPI_RXState = SPI_SYNC1;
uint8_t rxdata;
static uint8_t rxchksum;
 
if (SPITransferCompleted)
return; // return immediatly if transfer was completed
if (!(SPSR & (1 << SPIF)))
return; // return if no SPI-IRQ pending
SendSPI = 4; // mait 4 * 0.102 ms for the next call of SPI_TransmitByte() in the main loop
 
SLAVE_SELECT_PORT |= (1 << SPI_SLAVE_SELECT); // DeselectSlave
 
rxdata = SPDR; // save spi data register
 
switch (SPI_RXState) {
case SPI_SYNC1: // first sync byte
SPI_RxBufferIndex = 0; // set pointer to start of rx buffer
rxchksum = rxdata; // initialize checksum
if (rxdata == SPI_RXSYNCBYTE1) { // 1st Syncbyte found
SPI_RXState = SPI_SYNC2; // trigger to state for second sync byte
}
break;
 
case SPI_SYNC2: // second sync byte
if (rxdata == SPI_RXSYNCBYTE2) { // 2nd Syncbyte found
rxchksum += rxdata; // update checksum
SPI_RXState = SPI_DATA; // trigger to state for second sync byte
} else // 2nd Syncbyte not found
{
SPI_RXState = SPI_SYNC1; // jump back to 1st sync byte
}
break;
 
case SPI_DATA: // data bytes
SPI_RxBuffer[SPI_RxBufferIndex++] = rxdata; // copy data byte to spi buffer
// if all bytes are received of a packet from the NaviCtrl
if (SPI_RxBufferIndex >= SPI_RXBUFFER_LEN) { // last byte transfered is the checksum of the packet
if (rxdata == rxchksum) { // checksum matching?
// copy SPI_RxBuffer -> FromFlightCtrl
uint8_t *ptr = (uint8_t *) &fromNaviCtrl;
cli();
memcpy(ptr, (uint8_t *) SPI_RxBuffer, sizeof(fromNaviCtrl));
sei();
SPI_RxDataValid = 1;
} else { // checksum does not match
SPI_RxDataValid = 0; // reset valid flag
}
SPI_RXState = SPI_SYNC1; // reset state sync
} else { // not all bytes transfered
rxchksum += rxdata; // update checksum
}
break;
}// eof switch(SPI_RXState)
 
// if still some bytes left for transmission to NaviCtrl
if (SPI_TxBufferIndex < SPI_TXBUFFER_LEN) {
SLAVE_SELECT_PORT &= ~(1 << SPI_SLAVE_SELECT); // SelectSlave
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
asm volatile ("nop");
 
SPDR = SPI_TxBuffer[SPI_TxBufferIndex]; // transmit byte
toNaviCtrl.Chksum += SPI_TxBuffer[SPI_TxBufferIndex]; // update checksum for everey byte that was sent
SPI_TxBufferIndex++;
} else {
//Transfer of all bytes of the packet to NaviCtrl completed
SPITransferCompleted = 1;
}
}
/branches/dongfang_FC_rewrite/spi.h
13,26 → 13,26
#define SPI_CMD_VERSION 14
 
typedef struct {
uint8_t Sync1;
uint8_t Sync2;
uint8_t Command;
int16_t IntegralPitch;
int16_t IntegralRoll;
int16_t AccPitch;
int16_t AccRoll;
int16_t GyroHeading;
int16_t GyroPitch;
int16_t GyroRoll;
int16_t GyroYaw;
union {
int8_t sByte[12];
uint8_t Byte[12];
int16_t Int[6];
int32_t Long[3];
float Float[3];
} Param;
uint8_t Chksum;
} __attribute__((packed)) ToNaviCtrl_t;
uint8_t Sync1;
uint8_t Sync2;
uint8_t Command;
int16_t IntegralPitch;
int16_t IntegralRoll;
int16_t AccPitch;
int16_t AccRoll;
int16_t GyroHeading;
int16_t GyroPitch;
int16_t GyroRoll;
int16_t GyroYaw;
union {
int8_t sByte[12];
uint8_t Byte[12];
int16_t Int[6];
int32_t Long[3];
float Float[3];
} Param;
uint8_t Chksum;
}__attribute__((packed)) ToNaviCtrl_t;
 
#define SPI_CMD_OSD_DATA 100
#define SPI_CMD_GPS_POS 101
40,39 → 40,39
#define SPI_KALMAN 103
 
typedef struct {
uint8_t Command;
int16_t GPSStickPitch;
int16_t GPSStickRoll;
int16_t GPS_Yaw;
int16_t CompassHeading;
int16_t Status;
uint16_t BeepTime;
union {
int8_t Byte[12];
int16_t Int[6];
int32_t Long[3];
float Float[3];
} Param;
uint8_t Chksum;
} __attribute__((packed)) FromNaviCtrl_t;
uint8_t Command;
int16_t GPSStickPitch;
int16_t GPSStickRoll;
int16_t GPS_Yaw;
int16_t CompassHeading;
int16_t Status;
uint16_t BeepTime;
union {
int8_t Byte[12];
int16_t Int[6];
int32_t Long[3];
float Float[3];
} Param;
uint8_t Chksum;
}__attribute__((packed)) FromNaviCtrl_t;
 
typedef struct {
uint8_t Major;
uint8_t Minor;
uint8_t Patch;
uint8_t Compatible;
// unsigned char Hardware;
} __attribute__((packed)) SPI_VersionInfo_t;
uint8_t Major;
uint8_t Minor;
uint8_t Patch;
uint8_t Compatible;
// unsigned char Hardware;
}__attribute__((packed)) SPI_VersionInfo_t;
 
extern ToNaviCtrl_t toNaviCtrl;
extern FromNaviCtrl_t fromNaviCtrl;
extern ToNaviCtrl_t toNaviCtrl;
extern FromNaviCtrl_t fromNaviCtrl;
 
typedef struct {
int8_t KalmanK;
int8_t KalmanMaxDrift;
int8_t KalmanMaxFusion;
uint8_t SerialDataOkay;
} __attribute__((packed)) NCData_t;
int8_t KalmanK;
int8_t KalmanMaxDrift;
int8_t KalmanMaxFusion;
uint8_t SerialDataOkay;
}__attribute__((packed)) NCData_t;
 
extern uint8_t NCDataOkay;
extern uint8_t NCSerialDataOkay;
/branches/dongfang_FC_rewrite/timer0.c
77,134 → 77,141
// timer 0 is used for the PWM generation to control the offset voltage at the air pressure sensor
// Its overflow interrupt routine is used to generate the beep signal and the flight control motor update rate
void timer0_init(void) {
uint8_t sreg = SREG;
uint8_t sreg = SREG;
 
// disable all interrupts before reconfiguration
cli();
// disable all interrupts before reconfiguration
cli();
 
// Configure speaker port as output.
if(BoardRelease == 10) { // Speaker at PD2
DDRD |= (1<<DDD2);
PORTD &= ~(1<<PORTD2);
} else { // Speaker at PC7
DDRC |= (1<<DDC7);
PORTC &= ~(1<<PORTC7);
}
// Configure speaker port as output.
 
// set PB3 and PB4 as output for the PWM used as offset for the pressure sensor
DDRB |= (1<<DDB4)|(1<<DDB3);
PORTB &= ~((1<<PORTB4)|(1<<PORTB3));
if (BoardRelease == 10) { // Speaker at PD2
DDRD |= (1 << DDD2);
PORTD &= ~(1 << PORTD2);
} else { // Speaker at PC7
DDRC |= (1 << DDC7);
PORTC &= ~(1 << PORTC7);
}
 
// Timer/Counter 0 Control Register A
// set PB3 and PB4 as output for the PWM used as offset for the pressure sensor
DDRB |= (1 << DDB4) | (1 << DDB3);
PORTB &= ~((1 << PORTB4) | (1 << PORTB3));
 
// Waveform Generation Mode is Fast PWM (Bits WGM02 = 0, WGM01 = 1, WGM00 = 1)
// Clear OC0A on Compare Match, set OC0A at BOTTOM, noninverting PWM (Bits COM0A1 = 1, COM0A0 = 0)
// Clear OC0B on Compare Match, set OC0B at BOTTOM, (Bits COM0B1 = 1, COM0B0 = 0)
TCCR0A &= ~((1<<COM0A0)|(1<<COM0B0));
TCCR0A |= (1<<COM0A1)|(1<<COM0B1)|(1<<WGM01)|(1<<WGM00);
// Timer/Counter 0 Control Register A
 
// Timer/Counter 0 Control Register B
// Waveform Generation Mode is Fast PWM (Bits WGM02 = 0, WGM01 = 1, WGM00 = 1)
// Clear OC0A on Compare Match, set OC0A at BOTTOM, noninverting PWM (Bits COM0A1 = 1, COM0A0 = 0)
// Clear OC0B on Compare Match, set OC0B at BOTTOM, (Bits COM0B1 = 1, COM0B0 = 0)
TCCR0A &= ~((1 << COM0A0) | (1 << COM0B0));
TCCR0A |= (1 << COM0A1) | (1 << COM0B1) | (1 << WGM01) | (1 << WGM00);
 
// set clock divider for timer 0 to SYSKLOCK/8 = 20MHz / 8 = 2.5MHz
// i.e. the timer increments from 0x00 to 0xFF with an update rate of 2.5 MHz
// hence the timer overflow interrupt frequency is 2.5 MHz / 256 = 9.765 kHz
// Timer/Counter 0 Control Register B
 
// divider 8 (Bits CS02 = 0, CS01 = 1, CS00 = 0)
TCCR0B &= ~((1<<FOC0A)|(1<<FOC0B)|(1<<WGM02));
TCCR0B = (TCCR0B & 0xF8)|(0<<CS02)|(1<<CS01)|(0<<CS00);
// set clock divider for timer 0 to SYSKLOCK/8 = 20MHz / 8 = 2.5MHz
// i.e. the timer increments from 0x00 to 0xFF with an update rate of 2.5 MHz
// hence the timer overflow interrupt frequency is 2.5 MHz / 256 = 9.765 kHz
 
// initialize the Output Compare Register A & B used for PWM generation on port PB3 & PB4
OCR0A = 0; // for PB3
OCR0B = 120; // for PB4
// divider 8 (Bits CS02 = 0, CS01 = 1, CS00 = 0)
TCCR0B &= ~((1 << FOC0A) | (1 << FOC0B) | (1 << WGM02));
TCCR0B = (TCCR0B & 0xF8) | (0 << CS02) | (1 << CS01) | (0 << CS00);
 
// init Timer/Counter 0 Register
TCNT0 = 0;
// initialize the Output Compare Register A & B used for PWM generation on port PB3 & PB4
OCR0A = 0; // for PB3
OCR0B = 120; // for PB4
 
// Timer/Counter 0 Interrupt Mask Register
// enable timer overflow interrupt only
TIMSK0 &= ~((1<<OCIE0B)|(1<<OCIE0A));
TIMSK0 |= (1<<TOIE0);
// init Timer/Counter 0 Register
TCNT0 = 0;
 
SREG = sreg;
// Timer/Counter 0 Interrupt Mask Register
// enable timer overflow interrupt only
TIMSK0 &= ~((1 << OCIE0B) | (1 << OCIE0A));
TIMSK0 |= (1 << TOIE0);
 
SREG = sreg;
}
 
/*****************************************************/
/* Interrupt Routine of Timer 0 */
/*****************************************************/
ISR(TIMER0_OVF_vect) { // 9765.625 Hz
static uint8_t cnt_1ms = 1,cnt = 0;
uint8_t Beeper_On = 0;
ISR(TIMER0_OVF_vect)
{ // 9765.625 Hz
static uint8_t cnt_1ms = 1, cnt = 0;
uint8_t Beeper_On = 0;
 
#ifdef USE_NAVICTRL
if(SendSPI) SendSPI--; // if SendSPI is 0, the transmit of a byte via SPI bus to and from The Navicontrol is done
if(SendSPI) SendSPI--; // if SendSPI is 0, the transmit of a byte via SPI bus to and from The Navicontrol is done
#endif
if(!cnt--) { // every 10th run (9.765kHz/10 = 976Hz)
cnt = 9;
cnt_1ms^=1;
if(!cnt_1ms) {
runFlightControl = 1; // every 2nd run (976.5625 Hz/2 = 488.28125 Hz)
}
CountMilliseconds++; // increment millisecond counter
}
// beeper on if duration is not over
if(BeepTime) {
BeepTime--; // decrement BeepTime
if(BeepTime & BeepModulation) Beeper_On = 1;
else Beeper_On = 0;
}
else { // beeper off if duration is over
Beeper_On = 0;
BeepModulation = 0xFFFF;
}
// if beeper is on
if(Beeper_On) {
// set speaker port to high.
if(BoardRelease == 10) PORTD |= (1<<PORTD2); // Speaker at PD2
else PORTC |= (1<<PORTC7); // Speaker at PC7
} else { // beeper is off
// set speaker port to low
if(BoardRelease == 10) PORTD &= ~(1<<PORTD2);// Speaker at PD2
else PORTC &= ~(1<<PORTC7);// Speaker at PC7
}
 
if (!cnt--) { // every 10th run (9.765kHz/10 = 976Hz)
cnt = 9;
cnt_1ms ^= 1;
if (!cnt_1ms) {
runFlightControl = 1; // every 2nd run (976.5625 Hz/2 = 488.28125 Hz)
}
CountMilliseconds++; // increment millisecond counter
}
 
// beeper on if duration is not over
if (BeepTime) {
BeepTime--; // decrement BeepTime
if (BeepTime & BeepModulation)
Beeper_On = 1;
else
Beeper_On = 0;
} else { // beeper off if duration is over
Beeper_On = 0;
BeepModulation = 0xFFFF;
}
 
// if beeper is on
if (Beeper_On) {
// set speaker port to high.
if (BoardRelease == 10)
PORTD |= (1 << PORTD2); // Speaker at PD2
else
PORTC |= (1 << PORTC7); // Speaker at PC7
} else { // beeper is off
// set speaker port to low
if (BoardRelease == 10)
PORTD &= ~(1 << PORTD2);// Speaker at PD2
else
PORTC &= ~(1 << PORTC7);// Speaker at PC7
}
 
#ifndef USE_NAVICTRL
// update compass value if this option is enabled in the settings
if(staticParams.GlobalConfig & (CFG_COMPASS_ACTIVE|CFG_GPS_ACTIVE)) {
// update compass value if this option is enabled in the settings
if (staticParams.GlobalConfig & (CFG_COMPASS_ACTIVE | CFG_GPS_ACTIVE)) {
#ifdef USE_MK3MAG
MK3MAG_Update(); // read out mk3mag pwm
MK3MAG_Update(); // read out mk3mag pwm
#endif
}
}
#endif
}
 
// -----------------------------------------------------------------------
uint16_t SetDelay (uint16_t t) {
return(CountMilliseconds + t - 1);
uint16_t SetDelay(uint16_t t) {
return (CountMilliseconds + t - 1);
}
 
// -----------------------------------------------------------------------
int8_t CheckDelay(uint16_t t) {
return(((t - CountMilliseconds) & 0x8000) >> 8); // check sign bit
return (((t - CountMilliseconds) & 0x8000) >> 8); // check sign bit
}
 
// -----------------------------------------------------------------------
void Delay_ms(uint16_t w) {
uint16_t t_stop = SetDelay(w);
while (!CheckDelay(t_stop));
uint16_t t_stop = SetDelay(w);
while (!CheckDelay(t_stop))
;
}
 
// -----------------------------------------------------------------------
void Delay_ms_Mess(uint16_t w) {
uint16_t t_stop;
t_stop = SetDelay(w);
while (!CheckDelay(t_stop)) {
if(analogDataReady) {
analogDataReady = 0;
analog_start();
}
}
uint16_t t_stop;
t_stop = SetDelay(w);
while (!CheckDelay(t_stop)) {
if (analogDataReady) {
analogDataReady = 0;
analog_start();
}
}
}
/branches/dongfang_FC_rewrite/timer0.h
15,7 → 15,7
extern void timer0_init(void);
extern void Delay_ms(uint16_t w);
extern void Delay_ms_Mess(uint16_t w);
extern uint16_t SetDelay (uint16_t t);
extern int8_t CheckDelay (uint16_t t);
extern uint16_t SetDelay(uint16_t t);
extern int8_t CheckDelay(uint16_t t);
 
#endif //_TIMER0_H
/branches/dongfang_FC_rewrite/timer2.c
55,9 → 55,9
#include "rc.h"
#include "attitude.h"
 
volatile int16_t ServoPitchValue = 0;
volatile int16_t ServoRollValue = 0;
volatile uint8_t ServoActive = 0;
volatile int16_t ServoPitchValue = 0;
volatile int16_t ServoRollValue = 0;
volatile uint8_t ServoActive = 0;
 
#define HEF4017R_ON PORTC |= (1<<PORTC6)
#define HEF4017R_OFF PORTC &= ~(1<<PORTC6)
68,71 → 68,72
// The timer 2 is used to generate the PWM at PD7 (J7)
// to control a camera servo for pitch compensation.
void timer2_init(void) {
uint8_t sreg = SREG;
uint8_t sreg = SREG;
 
// disable all interrupts before reconfiguration
cli();
// disable all interrupts before reconfiguration
cli();
 
// set PD7 as output of the PWM for pitch servo
DDRD |= (1<<DDD7);
PORTD &= ~(1<<PORTD7); // set PD7 to low
// set PD7 as output of the PWM for pitch servo
DDRD |= (1 << DDD7);
PORTD &= ~(1 << PORTD7); // set PD7 to low
 
DDRC |= (1<<DDC6); // set PC6 as output (Reset for HEF4017)
//PORTC &= ~(1<<PORTC6); // set PC6 to low
HEF4017R_ON; // enable reset
DDRC |= (1 << DDC6); // set PC6 as output (Reset for HEF4017)
//PORTC &= ~(1<<PORTC6); // set PC6 to low
HEF4017R_ON; // enable reset
 
// Timer/Counter 2 Control Register A
// Timer/Counter 2 Control Register A
 
// Timer Mode is FastPWM with timer reload at OCR2A (Bits: WGM22 = 1, WGM21 = 1, WGM20 = 1)
// PD7: Normal port operation, OC2A disconnected, (Bits: COM2A1 = 0, COM2A0 = 0)
// PD6: Normal port operation, OC2B disconnected, (Bits: COM2B1 = 0, COM2B0 = 0)
TCCR2A &= ~((1<<COM2A1)|(1<<COM2A0)|(1<<COM2B1)|(1<<COM2B0));
TCCR2A |= (1<<WGM21)|(1<<WGM20);
// Timer Mode is FastPWM with timer reload at OCR2A (Bits: WGM22 = 1, WGM21 = 1, WGM20 = 1)
// PD7: Normal port operation, OC2A disconnected, (Bits: COM2A1 = 0, COM2A0 = 0)
// PD6: Normal port operation, OC2B disconnected, (Bits: COM2B1 = 0, COM2B0 = 0)
TCCR2A &= ~((1 << COM2A1) | (1 << COM2A0) | (1 << COM2B1) | (1 << COM2B0));
TCCR2A |= (1 << WGM21) | (1 << WGM20);
 
// Timer/Counter 2 Control Register B
// Timer/Counter 2 Control Register B
 
// Set clock divider for timer 2 to SYSKLOCK/32 = 20MHz / 32 = 625 kHz
// The timer increments from 0x00 to 0xFF with an update rate of 625 kHz or 1.6 us
// hence the timer overflow interrupt frequency is 625 kHz / 256 = 2.44 kHz or 0.4096 ms
// Set clock divider for timer 2 to SYSKLOCK/32 = 20MHz / 32 = 625 kHz
// The timer increments from 0x00 to 0xFF with an update rate of 625 kHz or 1.6 us
// hence the timer overflow interrupt frequency is 625 kHz / 256 = 2.44 kHz or 0.4096 ms
 
// divider 32 (Bits: CS022 = 0, CS21 = 1, CS20 = 1)
TCCR2B &= ~((1<<FOC2A)|(1<<FOC2B)|(1<<CS22));
TCCR2B |= (1<<CS21)|(1<<CS20)|(1<<WGM22);
// divider 32 (Bits: CS022 = 0, CS21 = 1, CS20 = 1)
TCCR2B &= ~((1 << FOC2A) | (1 << FOC2B) | (1 << CS22));
TCCR2B |= (1 << CS21) | (1 << CS20) | (1 << WGM22);
 
// Initialize the Timer/Counter 2 Register
TCNT2 = 0;
// Initialize the Timer/Counter 2 Register
TCNT2 = 0;
 
// Initialize the Output Compare Register A used for PWM generation on port PD7.
OCR2A = 255;
TCCR2A |= (1<<COM2A1); // set or clear at compare match depends on value of COM2A0
// Initialize the Output Compare Register A used for PWM generation on port PD7.
OCR2A = 255;
TCCR2A |= (1 << COM2A1); // set or clear at compare match depends on value of COM2A0
 
// Timer/Counter 2 Interrupt Mask Register
// Enable timer output compare match A Interrupt only
TIMSK2 &= ~((1<<OCIE2B)|(1<<TOIE2));
TIMSK2 |= (1<<OCIE2A);
// Timer/Counter 2 Interrupt Mask Register
// Enable timer output compare match A Interrupt only
TIMSK2 &= ~((1 << OCIE2B) | (1 << TOIE2));
TIMSK2 |= (1 << OCIE2A);
 
SREG = sreg;
SREG = sreg;
}
 
void Servo_On(void) {
ServoActive = 1;
ServoActive = 1;
}
 
void Servo_Off(void) {
ServoActive = 0;
HEF4017R_ON; // enable reset
ServoActive = 0;
HEF4017R_ON; // enable reset
}
 
/*****************************************************
* Control Servo Position
*****************************************************/
ISR(TIMER2_COMPA_vect) {
// frame len 22.5 ms = 14063 * 1.6 us
// stop pulse: 0.3 ms = 188 * 1.6 us
// min servo pulse: 0.6 ms = 375 * 1.6 us
// max servo pulse: 2.4 ms = 1500 * 1.6 us
// resolution: 1500 - 375 = 1125 steps
ISR(TIMER2_COMPA_vect)
{
// frame len 22.5 ms = 14063 * 1.6 us
// stop pulse: 0.3 ms = 188 * 1.6 us
// min servo pulse: 0.6 ms = 375 * 1.6 us
// max servo pulse: 2.4 ms = 1500 * 1.6 us
// resolution: 1500 - 375 = 1125 steps
 
#define PPM_STOPPULSE 188
#define PPM_FRAMELEN (1757 * .ServoRefresh) // 22.5 ms / 8 Channels = 2.8125ms per Servo Channel
#define MINSERVOPULSE 375
140,157 → 141,157
#define SERVORANGE (MAXSERVOPULSE - MINSERVOPULSE)
 
#if defined(USE_NON_4017_SERVO_OUTPUTS) || defined(USE_4017_SERVO_OUTPUTS)
static uint8_t isGeneratingPulse = 0;
static uint16_t remainingPulseLength = 0;
static uint16_t ServoFrameTime = 0;
static uint8_t ServoIndex = 0;
static uint8_t isGeneratingPulse = 0;
static uint16_t remainingPulseLength = 0;
static uint16_t ServoFrameTime = 0;
static uint8_t ServoIndex = 0;
 
#define MULTIPLIER 4
static int16_t ServoPitchOffset = (255 / 2) * MULTIPLIER; // initial value near center position
static int16_t ServoRollOffset = (255 / 2) * MULTIPLIER; // initial value near center position
static int16_t ServoPitchOffset = (255 / 2) * MULTIPLIER; // initial value near center position
static int16_t ServoRollOffset = (255 / 2) * MULTIPLIER; // initial value near center position
#endif
#ifdef USE_NON_4017_SERVO_OUTPUTS
//---------------------------
// Pitch servo state machine
//---------------------------
if (!isGeneratingPulse) { // pulse output complete on _next_ interrupt
if(TCCR2A & (1<<COM2A0)) { // we are still outputting a high pulse
TCCR2A &= ~(1<<COM2A0); // make a low pulse on _next_ interrupt, and now
remainingPulseLength = MINSERVOPULSE + SERVORANGE / 2; // center position ~ 1.5ms
ServoPitchOffset = (ServoPitchOffset * 3 + (int16_t)dynamicParams.ServoPitchControl) / 4; // lowpass offset
if(staticParams.ServoPitchCompInvert & 0x01) {
// inverting movement of servo
// todo: function.
ServoPitchValue = ServoPitchOffset + (int16_t)(((int32_t)staticParams.ServoPitchComp (integralGyroPitch / 128L )) / (256L));
} else {
// todo: function.
// non inverting movement of servo
ServoPitchValue = ServoPitchOffset - (int16_t)(((int32_t)staticParams.ServoPitchComp (integralGyroPitch / 128L )) / (256L));
}
// limit servo value to its parameter range definition
if(ServoPitchValue < (int16_t)staticParams.ServoPitchMin) {
ServoPitchValue = (int16_t)staticParams.ServoPitchMin;
} else if(ServoPitchValue > (int16_t)staticParams.ServoPitchMax) {
ServoPitchValue = (int16_t)staticParams.ServoPitchMax;
}
remainingPulseLength = (ServoPitchValue - 256 / 2) * MULTIPLIER; // shift ServoPitchValue to center position
// range servo pulse width
if(remainingPulseLength > MAXSERVOPULSE ) remainingPulseLength = MAXSERVOPULSE; // upper servo pulse limit
else if(remainingPulseLength < MINSERVOPULSE) remainingPulseLength = MINSERVOPULSE; // lower servo pulse limit
//---------------------------
// Pitch servo state machine
//---------------------------
if (!isGeneratingPulse) { // pulse output complete on _next_ interrupt
if(TCCR2A & (1<<COM2A0)) { // we are still outputting a high pulse
TCCR2A &= ~(1<<COM2A0); // make a low pulse on _next_ interrupt, and now
remainingPulseLength = MINSERVOPULSE + SERVORANGE / 2; // center position ~ 1.5ms
ServoPitchOffset = (ServoPitchOffset * 3 + (int16_t)dynamicParams.ServoPitchControl) / 4; // lowpass offset
if(staticParams.ServoPitchCompInvert & 0x01) {
// inverting movement of servo
// todo: function.
ServoPitchValue = ServoPitchOffset + (int16_t)(((int32_t)staticParams.ServoPitchComp (integralGyroPitch / 128L )) / (256L));
} else {
// todo: function.
// non inverting movement of servo
ServoPitchValue = ServoPitchOffset - (int16_t)(((int32_t)staticParams.ServoPitchComp (integralGyroPitch / 128L )) / (256L));
}
// limit servo value to its parameter range definition
if(ServoPitchValue < (int16_t)staticParams.ServoPitchMin) {
ServoPitchValue = (int16_t)staticParams.ServoPitchMin;
} else if(ServoPitchValue > (int16_t)staticParams.ServoPitchMax) {
ServoPitchValue = (int16_t)staticParams.ServoPitchMax;
}
 
// accumulate time for correct update rate
ServoFrameTime = remainingPulseLength;
} else { // we had a high pulse
TCCR2A |= (1<<COM2A0); // make a low pulse
remainingPulseLength = PPM_FRAMELEN - ServoFrameTime;
}
// set pulse output active
isGeneratingPulse = 1;
} // EOF Pitch servo state machine
remainingPulseLength = (ServoPitchValue - 256 / 2) * MULTIPLIER; // shift ServoPitchValue to center position
 
// range servo pulse width
if(remainingPulseLength > MAXSERVOPULSE ) remainingPulseLength = MAXSERVOPULSE; // upper servo pulse limit
else if(remainingPulseLength < MINSERVOPULSE) remainingPulseLength = MINSERVOPULSE; // lower servo pulse limit
 
// accumulate time for correct update rate
ServoFrameTime = remainingPulseLength;
} else { // we had a high pulse
TCCR2A |= (1<<COM2A0); // make a low pulse
remainingPulseLength = PPM_FRAMELEN - ServoFrameTime;
}
// set pulse output active
isGeneratingPulse = 1;
} // EOF Pitch servo state machine
 
#elseif defined(USE_4017_SERVOS)
//-----------------------------------------------------
// PPM state machine, onboard demultiplexed by HEF4017
//-----------------------------------------------------
if(!isGeneratingPulse) { // pulse output complete
if(TCCR2A & (1<<COM2A0)) { // we had a low pulse
TCCR2A &= ~(1<<COM2A0);// make a high pulse
if(ServoIndex == 0) { // if we are at the sync gap
remainingPulseLength = PPM_FRAMELEN - ServoFrameTime; // generate sync gap by filling time to full frame time
ServoFrameTime = 0; // reset servo frame time
HEF4017R_ON; // enable HEF4017 reset
} else { // servo channels
remainingPulseLength = MINSERVOPULSE + SERVORANGE/2; // center position ~ 1.5ms
switch(ServoIndex) { // map servo channels
case 1: // Pitch Compensation Servo
ServoPitchOffset = (ServoPitchOffset * 3 + (int16_t)dynamicParams.ServoPitchControl * MULTIPLIER) / 4; // lowpass offset
ServoPitchValue = ServoPitchOffset; // offset (Range from 0 to 255 * 3 = 765)
if(staticParams.ServoPitchCompInvert & 0x01) {
// inverting movement of servo
ServoPitchValue += (int16_t)( ( (int32_t)staticParams.ServoPitchComp * MULTIPLIER * (integralGyroPitch / 128L ) ) / (256L) );
} else { // non inverting movement of servo
ServoPitchValue -= (int16_t)( ( (int32_t)staticParams.ServoPitchComp * MULTIPLIER * (integralGyroPitch / 128L ) ) / (256L) );
//-----------------------------------------------------
// PPM state machine, onboard demultiplexed by HEF4017
//-----------------------------------------------------
if(!isGeneratingPulse) { // pulse output complete
if(TCCR2A & (1<<COM2A0)) { // we had a low pulse
TCCR2A &= ~(1<<COM2A0);// make a high pulse
 
if(ServoIndex == 0) { // if we are at the sync gap
remainingPulseLength = PPM_FRAMELEN - ServoFrameTime; // generate sync gap by filling time to full frame time
ServoFrameTime = 0; // reset servo frame time
HEF4017R_ON; // enable HEF4017 reset
} else { // servo channels
remainingPulseLength = MINSERVOPULSE + SERVORANGE/2; // center position ~ 1.5ms
switch(ServoIndex) { // map servo channels
case 1: // Pitch Compensation Servo
ServoPitchOffset = (ServoPitchOffset * 3 + (int16_t)dynamicParams.ServoPitchControl * MULTIPLIER) / 4; // lowpass offset
ServoPitchValue = ServoPitchOffset; // offset (Range from 0 to 255 * 3 = 765)
if(staticParams.ServoPitchCompInvert & 0x01) {
// inverting movement of servo
ServoPitchValue += (int16_t)( ( (int32_t)staticParams.ServoPitchComp * MULTIPLIER * (integralGyroPitch / 128L ) ) / (256L) );
} else { // non inverting movement of servo
ServoPitchValue -= (int16_t)( ( (int32_t)staticParams.ServoPitchComp * MULTIPLIER * (integralGyroPitch / 128L ) ) / (256L) );
}
// limit servo value to its parameter range definition
if(ServoPitchValue < ((int16_t)staticParams.ServoPitchMin * MULTIPLIER)) {
ServoPitchValue = (int16_t)staticParams.ServoPitchMin * MULTIPLIER;
} else if(ServoPitchValue > ((int16_t)staticParams.ServoPitchMax * MULTIPLIER)) {
ServoPitchValue = (int16_t)staticParams.ServoPitchMax * MULTIPLIER;
}
remainingPulseLength += ServoPitchValue - (256 / 2) * MULTIPLIER; // shift ServoPitchValue to center position
ServoPitchValue /= MULTIPLIER;
break;
 
case 2: // Roll Compensation Servo
ServoRollOffset = (ServoRollOffset * 3 + (int16_t)80 * MULTIPLIER) / 4; // lowpass offset
ServoRollValue = ServoRollOffset; // offset (Range from 0 to 255 * 3 = 765)
//if(staticParams.ServoRollCompInvert & 0x01)
{ // inverting movement of servo
ServoRollValue += (int16_t)( ( (int32_t) 50 * MULTIPLIER * (integralGyroRoll / 128L ) ) / (256L) );
}
/* else
{ // non inverting movement of servo
ServoRollValue -= (int16_t)( ( (int32_t) 40 * MULTIPLIER * (IntegralGyroRoll / 128L ) ) / (256L) );
}
*/// limit servo value to its parameter range definition
if(ServoRollValue < ((int16_t)staticParams.ServoPitchMin * MULTIPLIER)) {
ServoRollValue = (int16_t)staticParams.ServoPitchMin * MULTIPLIER;
} else if(ServoRollValue > ((int16_t)staticParams.ServoPitchMax * MULTIPLIER)) {
ServoRollValue = (int16_t)staticParams.ServoPitchMax * MULTIPLIER;
}
remainingPulseLength += ServoRollValue - (256 / 2) * MULTIPLIER; // shift ServoRollValue to center position
ServoRollValue /= MULTIPLIER;
break;
 
default: // other servo channels
remainingPulseLength += 2 * PPM_in[ServoIndex]; // add channel value, factor of 2 because timer 1 increments 3.2µs
break;
}
// range servo pulse width
if(remainingPulseLength > MAXSERVOPULSE) remainingPulseLength = MAXSERVOPULSE; // upper servo pulse limit
else if(remainingPulseLength < MINSERVOPULSE) remainingPulseLength = MINSERVOPULSE; // lower servo pulse limit
// substract stop pulse width
remainingPulseLength -= PPM_STOPPULSE;
// accumulate time for correct sync gap
ServoFrameTime += remainingPulseLength;
}
} else { // we had a high pulse
TCCR2A |= (1<<COM2A0); // make a low pulse
// set pulsewidth to stop pulse width
remainingPulseLength = PPM_STOPPULSE;
// accumulate time for correct sync gap
ServoFrameTime += remainingPulseLength;
if(ServoActive && RC_Quality > 180) HEF4017R_OFF; // disable HEF4017 reset
ServoIndex++; // change to next servo channel
if(ServoIndex > staticParams.ServoRefresh) ServoIndex = 0; // reset to the sync gap
}
// set pulse output active
isGeneratingPulse = 1;
}
// limit servo value to its parameter range definition
if(ServoPitchValue < ((int16_t)staticParams.ServoPitchMin * MULTIPLIER)) {
ServoPitchValue = (int16_t)staticParams.ServoPitchMin * MULTIPLIER;
} else if(ServoPitchValue > ((int16_t)staticParams.ServoPitchMax * MULTIPLIER)) {
ServoPitchValue = (int16_t)staticParams.ServoPitchMax * MULTIPLIER;
}
remainingPulseLength += ServoPitchValue - (256 / 2) * MULTIPLIER; // shift ServoPitchValue to center position
ServoPitchValue /= MULTIPLIER;
break;
case 2: // Roll Compensation Servo
ServoRollOffset = (ServoRollOffset * 3 + (int16_t)80 * MULTIPLIER) / 4; // lowpass offset
ServoRollValue = ServoRollOffset; // offset (Range from 0 to 255 * 3 = 765)
//if(staticParams.ServoRollCompInvert & 0x01)
{ // inverting movement of servo
ServoRollValue += (int16_t)( ( (int32_t) 50 * MULTIPLIER * (integralGyroRoll / 128L ) ) / (256L) );
}
/* else
{ // non inverting movement of servo
ServoRollValue -= (int16_t)( ( (int32_t) 40 * MULTIPLIER * (IntegralGyroRoll / 128L ) ) / (256L) );
}
*/ // limit servo value to its parameter range definition
if(ServoRollValue < ((int16_t)staticParams.ServoPitchMin * MULTIPLIER)) {
ServoRollValue = (int16_t)staticParams.ServoPitchMin * MULTIPLIER;
} else if(ServoRollValue > ((int16_t)staticParams.ServoPitchMax * MULTIPLIER)) {
ServoRollValue = (int16_t)staticParams.ServoPitchMax * MULTIPLIER;
}
remainingPulseLength += ServoRollValue - (256 / 2) * MULTIPLIER; // shift ServoRollValue to center position
ServoRollValue /= MULTIPLIER;
break;
default: // other servo channels
remainingPulseLength += 2 * PPM_in[ServoIndex]; // add channel value, factor of 2 because timer 1 increments 3.2µs
break;
}
// range servo pulse width
if(remainingPulseLength > MAXSERVOPULSE) remainingPulseLength = MAXSERVOPULSE; // upper servo pulse limit
else if(remainingPulseLength < MINSERVOPULSE) remainingPulseLength = MINSERVOPULSE; // lower servo pulse limit
// substract stop pulse width
remainingPulseLength -= PPM_STOPPULSE;
// accumulate time for correct sync gap
ServoFrameTime += remainingPulseLength;
}
} else { // we had a high pulse
TCCR2A |= (1<<COM2A0); // make a low pulse
// set pulsewidth to stop pulse width
remainingPulseLength = PPM_STOPPULSE;
// accumulate time for correct sync gap
ServoFrameTime += remainingPulseLength;
if(ServoActive && RC_Quality > 180) HEF4017R_OFF; // disable HEF4017 reset
ServoIndex++; // change to next servo channel
if(ServoIndex > staticParams.ServoRefresh) ServoIndex = 0; // reset to the sync gap
}
// set pulse output active
isGeneratingPulse = 1;
}
#endif
 
/*
* Cases:
* 1) 255 + 128 <= remainingPulseLength --> delta = 255
* 2) 255 <= remainingPulseLength < 255 + 128 --> delta = 255 - 128
* this is to avoid a too short delta on the last cycle, which would cause
* an interupt-on-interrupt condition and the loss of the last interrupt.
* 3) remainingPulseLength < 255 --> delta = remainingPulseLength
*/
/*
* Cases:
* 1) 255 + 128 <= remainingPulseLength --> delta = 255
* 2) 255 <= remainingPulseLength < 255 + 128 --> delta = 255 - 128
* this is to avoid a too short delta on the last cycle, which would cause
* an interupt-on-interrupt condition and the loss of the last interrupt.
* 3) remainingPulseLength < 255 --> delta = remainingPulseLength
*/
#if defined(USE_NON_4017_SERVO_OUTPUTS) || defined(USE_4017_SERVO_OUTPUTS)
uint8_t delta;
if (remainingPulseLength >= (255 + 128)) {
delta = 255;
} else if (remainingPulseLength >= 255) {
delta = 255- 128;
} else {
delta = remainingPulseLength;
isGeneratingPulse = 0; // trigger to stop pulse
}
OCR2A = delta;
remainingPulseLength -= delta;
uint8_t delta;
if (remainingPulseLength >= (255 + 128)) {
delta = 255;
} else if (remainingPulseLength >= 255) {
delta = 255- 128;
} else {
delta = remainingPulseLength;
isGeneratingPulse = 0; // trigger to stop pulse
}
OCR2A = delta;
remainingPulseLength -= delta;
#endif
}
/branches/dongfang_FC_rewrite/twimaster.c
59,12 → 59,12
#include "configuration.h"
#include "printf_P.h"
 
volatile uint8_t twi_state = TWI_STATE_MOTOR_TX;
volatile uint8_t dac_channel = 0;
volatile uint8_t motor_write = 0;
volatile uint8_t motor_read = 0;
volatile uint16_t I2CTimeout = 100;
uint8_t missingMotor = 0;
volatile uint8_t twi_state = TWI_STATE_MOTOR_TX;
volatile uint8_t dac_channel = 0;
volatile uint8_t motor_write = 0;
volatile uint8_t motor_read = 0;
volatile uint16_t I2CTimeout = 100;
uint8_t missingMotor = 0;
 
MotorData_t motor[MAX_MOTORS];
 
78,36 → 78,36
* Initialize I2C (TWI)
**************************************************/
void I2C_init(void) {
uint8_t i;
uint8_t sreg = SREG;
cli();
// SDA is INPUT
DDRC &= ~(1<<DDC1);
// SCL is output
DDRC |= (1<<DDC0);
// pull up SDA
PORTC |= (1<<PORTC0)|(1<<PORTC1);
// TWI Status Register
// prescaler 1 (TWPS1 = 0, TWPS0 = 0)
TWSR &= ~((1<<TWPS1)|(1<<TWPS0));
// set TWI Bit Rate Register
TWBR = ((SYSCLK/SCL_CLOCK)-16)/2;
twi_state = TWI_STATE_MOTOR_TX;
motor_write = 0;
motor_read = 0;
for(i=0; i < MAX_MOTORS; i++) {
motor[i].SetPoint = 0;
motor[i].Present = 0;
motor[i].Error = 0;
motor[i].MaxPWM = 0;
}
SREG = sreg;
uint8_t i;
uint8_t sreg = SREG;
cli();
 
// SDA is INPUT
DDRC &= ~(1 << DDC1);
// SCL is output
DDRC |= (1 << DDC0);
// pull up SDA
PORTC |= (1 << PORTC0) | (1 << PORTC1);
 
// TWI Status Register
// prescaler 1 (TWPS1 = 0, TWPS0 = 0)
TWSR &= ~((1 << TWPS1) | (1 << TWPS0));
 
// set TWI Bit Rate Register
TWBR = ((SYSCLK / SCL_CLOCK) - 16) / 2;
 
twi_state = TWI_STATE_MOTOR_TX;
motor_write = 0;
motor_read = 0;
 
for (i = 0; i < MAX_MOTORS; i++) {
motor[i].SetPoint = 0;
motor[i].Present = 0;
motor[i].Error = 0;
motor[i].MaxPWM = 0;
}
 
SREG = sreg;
}
 
/****************************************
114,16 → 114,16
* Start I2C
****************************************/
void I2C_Start(uint8_t start_state) {
twi_state = start_state;
// TWI Control Register
// clear TWI interrupt flag (TWINT=1)
// disable TWI Acknowledge Bit (TWEA = 0)
// enable TWI START Condition Bit (TWSTA = 1), MASTER
// disable TWI STOP Condition Bit (TWSTO = 0)
// disable TWI Write Collision Flag (TWWC = 0)
// enable i2c (TWEN = 1)
// enable TWI Interrupt (TWIE = 1)
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN) | (1<<TWIE);
twi_state = start_state;
// TWI Control Register
// clear TWI interrupt flag (TWINT=1)
// disable TWI Acknowledge Bit (TWEA = 0)
// enable TWI START Condition Bit (TWSTA = 1), MASTER
// disable TWI STOP Condition Bit (TWSTO = 0)
// disable TWI Write Collision Flag (TWWC = 0)
// enable i2c (TWEN = 1)
// enable TWI Interrupt (TWIE = 1)
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN) | (1 << TWIE);
}
 
/****************************************
130,16 → 130,16
* Stop I2C
****************************************/
void I2C_Stop(uint8_t start_state) {
twi_state = start_state;
// TWI Control Register
// clear TWI interrupt flag (TWINT=1)
// disable TWI Acknowledge Bit (TWEA = 0)
// diable TWI START Condition Bit (TWSTA = 1), no MASTER
// enable TWI STOP Condition Bit (TWSTO = 1)
// disable TWI Write Collision Flag (TWWC = 0)
// enable i2c (TWEN = 1)
// disable TWI Interrupt (TWIE = 0)
TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN);
twi_state = start_state;
// TWI Control Register
// clear TWI interrupt flag (TWINT=1)
// disable TWI Acknowledge Bit (TWEA = 0)
// diable TWI START Condition Bit (TWSTA = 1), no MASTER
// enable TWI STOP Condition Bit (TWSTO = 1)
// disable TWI Write Collision Flag (TWWC = 0)
// enable i2c (TWEN = 1)
// disable TWI Interrupt (TWIE = 0)
TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
}
 
/****************************************
146,12 → 146,12
* Write to I2C
****************************************/
void I2C_WriteByte(int8_t byte) {
// move byte to send into TWI Data Register
TWDR = byte;
// clear interrupt flag (TWINT = 1)
// enable i2c bus (TWEN = 1)
// enable interrupt (TWIE = 1)
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE);
// move byte to send into TWI Data Register
TWDR = byte;
// clear interrupt flag (TWINT = 1)
// enable i2c bus (TWEN = 1)
// enable interrupt (TWIE = 1)
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE);
}
 
/****************************************
158,14 → 158,14
* Receive byte and send ACK
****************************************/
void I2C_ReceiveByte(void) {
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE) | (1<<TWEA);
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE) | (1 << TWEA);
}
 
/****************************************
* I2C receive last byte and send no ACK
****************************************/
void I2C_ReceiveLastByte(void){
TWCR = (1<<TWINT) | (1<<TWEN) | (1<<TWIE);
void I2C_ReceiveLastByte(void) {
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWIE);
}
 
/****************************************
172,139 → 172,148
* Reset I2C
****************************************/
void I2C_Reset(void) {
// stop i2c bus
I2C_Stop(TWI_STATE_MOTOR_TX);
twi_state = 0;
motor_write = TWDR;
motor_write = 0;
motor_read = 0;
TWCR = (1<<TWINT); // reset to original state incl. interrupt flag reset
TWAMR = 0;
TWAR = 0;
TWDR = 0;
TWSR = 0;
TWBR = 0;
I2C_init();
I2C_Start(TWI_STATE_MOTOR_TX);
// stop i2c bus
I2C_Stop(TWI_STATE_MOTOR_TX);
twi_state = 0;
motor_write = TWDR;
motor_write = 0;
motor_read = 0;
TWCR = (1 << TWINT); // reset to original state incl. interrupt flag reset
TWAMR = 0;
TWAR = 0;
TWDR = 0;
TWSR = 0;
TWBR = 0;
I2C_init();
I2C_Start(TWI_STATE_MOTOR_TX);
}
 
/****************************************
* I2C ISR
****************************************/
ISR (TWI_vect) {
static uint8_t missing_motor = 0;
switch (twi_state++) { // First i2c_start from SendMotorData()
// Master Transmit
case 0: // TWI_STATE_MOTOR_TX
// skip motor if not used in mixer
while((Mixer.Motor[motor_write][MIX_THROTTLE] <= 0) && (motor_write < MAX_MOTORS)) motor_write++;
if(motor_write >= MAX_MOTORS) { // writing finished, read now
motor_write = 0;
twi_state = TWI_STATE_MOTOR_RX;
I2C_WriteByte(0x53 + (motor_read * 2)); // select slave adress in rx mode
}
else I2C_WriteByte(0x52 + (motor_write * 2)); // select slave adress in tx mode
break;
case 1: // Send Data to Slave
I2C_WriteByte(motor[motor_write].SetPoint); // transmit rotation rate setpoint
break;
case 2: // repeat case 0+1 for all motors
if(TWSR == TW_MT_DATA_NACK) { // Data transmitted, NACK received
if(!missing_motor) missing_motor = motor_write + 1;
if(++motor[motor_write].Error == 0) motor[motor_write].Error = 255; // increment error counter and handle overflow
}
I2C_Stop(TWI_STATE_MOTOR_TX);
I2CTimeout = 10;
motor_write++; // next motor
I2C_Start(TWI_STATE_MOTOR_TX); // Repeated start -> switch slave or switch Master Transmit -> Master Receive
break;
// Master Receive Data
case 3:
if(TWSR != TW_MR_SLA_ACK) { // SLA+R transmitted, if not ACK received
// no response from the addressed slave received
motor[motor_read].Present = 0;
motor_read++; // next motor
if(motor_read >= MAX_MOTORS) motor_read = 0; // restart reading of first motor if we have reached the last one
I2C_Stop(TWI_STATE_MOTOR_TX);
} else {
motor[motor_read].Present = ('1' - '-') + motor_read;
I2C_ReceiveByte(); //Transmit 1st byte
}
missingMotor = missing_motor;
missing_motor = 0;
break;
case 4: //Read 1st byte and transmit 2nd Byte
motor[motor_read].Current = TWDR;
I2C_ReceiveLastByte(); // nack
break;
case 5:
//Read 2nd byte
motor[motor_read].MaxPWM = TWDR;
motor_read++; // next motor
if(motor_read >= MAX_MOTORS) motor_read = 0; // restart reading of first motor if we have reached the last one
I2C_Stop(TWI_STATE_MOTOR_TX);
break;
// Writing ADC values.
case 7:
I2C_WriteByte(0x98); // Address the DAC
break;
case 8:
I2C_WriteByte(0x10 + (DACChannel << 1)); // Select DAC Channel (0x10 = A, 0x12 = B, 0x14 = C)
break;
case 9:
I2C_WriteByte(DACValues[DACChannel]);
break;
case 10:
I2C_WriteByte(0x80); // 2nd byte for all channels is 0x80
break;
case 11:
I2C_Stop(TWI_STATE_MOTOR_TX);
I2CTimeout = 10;
// repeat case 7...10 until all DAC Channels are updated
if(DACChannel < 2) {
DACChannel ++; // jump to next channel
I2C_Start(TWI_STATE_GYRO_OFFSET_TX); // start transmission for next channel
} else {
DACChannel = 0; // reset dac channel counter
}
break;
default:
I2C_Stop(TWI_STATE_MOTOR_TX);
I2CTimeout = 10;
motor_write = 0;
motor_read = 0;
}
ISR (TWI_vect)
{
static uint8_t missing_motor = 0;
switch (twi_state++) { // First i2c_start from SendMotorData()
// Master Transmit
case 0: // TWI_STATE_MOTOR_TX
// skip motor if not used in mixer
while ((Mixer.Motor[motor_write][MIX_THROTTLE] <= 0) && (motor_write
< MAX_MOTORS))
motor_write++;
if (motor_write >= MAX_MOTORS) { // writing finished, read now
motor_write = 0;
twi_state = TWI_STATE_MOTOR_RX;
I2C_WriteByte(0x53 + (motor_read * 2)); // select slave adress in rx mode
} else
I2C_WriteByte(0x52 + (motor_write * 2)); // select slave adress in tx mode
break;
case 1: // Send Data to Slave
I2C_WriteByte(motor[motor_write].SetPoint); // transmit rotation rate setpoint
break;
case 2: // repeat case 0+1 for all motors
if (TWSR == TW_MT_DATA_NACK) { // Data transmitted, NACK received
if (!missing_motor)
missing_motor = motor_write + 1;
if (++motor[motor_write].Error == 0)
motor[motor_write].Error = 255; // increment error counter and handle overflow
}
I2C_Stop(TWI_STATE_MOTOR_TX);
I2CTimeout = 10;
motor_write++; // next motor
I2C_Start(TWI_STATE_MOTOR_TX); // Repeated start -> switch slave or switch Master Transmit -> Master Receive
break;
// Master Receive Data
case 3:
if (TWSR != TW_MR_SLA_ACK) { // SLA+R transmitted, if not ACK received
// no response from the addressed slave received
motor[motor_read].Present = 0;
motor_read++; // next motor
if (motor_read >= MAX_MOTORS)
motor_read = 0; // restart reading of first motor if we have reached the last one
I2C_Stop(TWI_STATE_MOTOR_TX);
} else {
motor[motor_read].Present = ('1' - '-') + motor_read;
I2C_ReceiveByte(); //Transmit 1st byte
}
missingMotor = missing_motor;
missing_motor = 0;
break;
case 4: //Read 1st byte and transmit 2nd Byte
motor[motor_read].Current = TWDR;
I2C_ReceiveLastByte(); // nack
break;
case 5:
//Read 2nd byte
motor[motor_read].MaxPWM = TWDR;
motor_read++; // next motor
if (motor_read >= MAX_MOTORS)
motor_read = 0; // restart reading of first motor if we have reached the last one
I2C_Stop(TWI_STATE_MOTOR_TX);
break;
 
// Writing ADC values.
case 7:
I2C_WriteByte(0x98); // Address the DAC
break;
 
case 8:
I2C_WriteByte(0x10 + (DACChannel << 1)); // Select DAC Channel (0x10 = A, 0x12 = B, 0x14 = C)
break;
 
case 9:
I2C_WriteByte(DACValues[DACChannel]);
break;
 
case 10:
I2C_WriteByte(0x80); // 2nd byte for all channels is 0x80
break;
 
case 11:
I2C_Stop(TWI_STATE_MOTOR_TX);
I2CTimeout = 10;
// repeat case 7...10 until all DAC Channels are updated
if (DACChannel < 2) {
DACChannel++; // jump to next channel
I2C_Start(TWI_STATE_GYRO_OFFSET_TX); // start transmission for next channel
} else {
DACChannel = 0; // reset dac channel counter
}
break;
 
default:
I2C_Stop(TWI_STATE_MOTOR_TX);
I2CTimeout = 10;
motor_write = 0;
motor_read = 0;
}
}
 
extern void twi_diagnostics(void) {
// Check connected BL-Ctrls
uint8_t i;
printf("\n\rFound BL-Ctrl: ");
for(i = 0; i < MAX_MOTORS; i++) {
motor[i].SetPoint = 0;
}
// Check connected BL-Ctrls
uint8_t i;
 
I2C_Start(TWI_STATE_MOTOR_TX);
_delay_ms(2);
motor_read = 0; // read the first I2C-Data
printf("\n\rFound BL-Ctrl: ");
 
for(i = 0; i < MAX_MOTORS; i++) {
I2C_Start(TWI_STATE_MOTOR_TX);
_delay_ms(2);
if(motor[i].Present) printf("%d ",i+1);
}
for (i = 0; i < MAX_MOTORS; i++) {
motor[i].SetPoint = 0;
}
 
for(i = 0; i < MAX_MOTORS; i++) {
if(!motor[i].Present && Mixer.Motor[i][MIX_THROTTLE] > 0) printf("\n\r\n\r!! MISSING BL-CTRL: %d !!",i + 1);
motor[i].Error = 0;
}
I2C_Start(TWI_STATE_MOTOR_TX);
_delay_ms(2);
 
motor_read = 0; // read the first I2C-Data
 
for (i = 0; i < MAX_MOTORS; i++) {
I2C_Start(TWI_STATE_MOTOR_TX);
_delay_ms(2);
if (motor[i].Present)
printf("%d ",i+1);
}
 
for (i = 0; i < MAX_MOTORS; i++) {
if (!motor[i].Present && Mixer.Motor[i][MIX_THROTTLE] > 0)
printf("\n\r\n\r!! MISSING BL-CTRL: %d !!",i + 1);
motor[i].Error = 0;
}
}
/branches/dongfang_FC_rewrite/twimaster.h
14,12 → 14,12
volatile extern uint8_t DACValues[4];
 
typedef struct {
uint8_t SetPoint; // written by attitude controller
uint8_t Present; // 0 if BL was found
uint8_t Error; // I2C error counter
uint8_t Current; // read byck from BL
uint8_t MaxPWM; // read back from BL
} __attribute__((packed)) MotorData_t;
uint8_t SetPoint; // written by attitude controller
uint8_t Present; // 0 if BL was found
uint8_t Error; // I2C error counter
uint8_t Current; // read byck from BL
uint8_t MaxPWM; // read back from BL
}__attribute__((packed)) MotorData_t;
 
#define MAX_MOTORS 12
extern MotorData_t motor[MAX_MOTORS];
26,9 → 26,9
 
extern volatile uint16_t I2CTimeout;
 
extern void I2C_init (void); // Initialize I2C
extern void I2C_init(void); // Initialize I2C
extern void I2C_Start(uint8_t start_state); // Start I2C
extern void I2C_Stop (uint8_t start_state); // Stop I2C
extern void I2C_Stop(uint8_t start_state); // Stop I2C
extern void I2C_Reset(void); // Reset I2C
extern void twi_diagnostics(void);
 
/branches/dongfang_FC_rewrite/uart0.c
77,16 → 77,16
#define FALSE 0
#define TRUE 1
//int8_t test __attribute__ ((section (".noinit")));
uint8_t request_VerInfo = FALSE;
uint8_t request_ExternalControl = FALSE;
uint8_t request_Display = FALSE;
uint8_t request_Display1 = FALSE;
uint8_t request_DebugData = FALSE;
uint8_t request_Data3D = FALSE;
uint8_t request_DebugLabel = 255;
uint8_t request_PPMChannels = FALSE;
uint8_t request_MotorTest = FALSE;
uint8_t request_variables = FALSE;
uint8_t request_VerInfo = FALSE;
uint8_t request_ExternalControl = FALSE;
uint8_t request_Display = FALSE;
uint8_t request_Display1 = FALSE;
uint8_t request_DebugData = FALSE;
uint8_t request_Data3D = FALSE;
uint8_t request_DebugLabel = 255;
uint8_t request_PPMChannels = FALSE;
uint8_t request_MotorTest = FALSE;
uint8_t request_variables = FALSE;
 
uint8_t DisplayLine = 0;
 
98,17 → 98,17
volatile uint8_t *pRxData = 0;
volatile uint8_t RxDataLen = 0;
 
uint8_t motorTestActive = 0;
uint8_t motorTest[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
uint8_t motorTestActive = 0;
uint8_t motorTest[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
uint8_t ConfirmFrame;
 
typedef struct {
int16_t Heading;
} __attribute__((packed)) Heading_t;
int16_t Heading;
}__attribute__((packed)) Heading_t;
 
DebugOut_t DebugOut;
Data3D_t Data3D;
UART_VersionInfo_t UART_VersionInfo;
DebugOut_t DebugOut;
Data3D_t Data3D;
UART_VersionInfo_t UART_VersionInfo;
 
uint16_t DebugData_Timer;
uint16_t Data3D_Timer;
121,210 → 121,211
 
// keep lables in flash to save 512 bytes of sram space
const prog_uint8_t ANALOG_LABEL[32][16] = {
//1234567890123456
"AnglePitch ", //0
"AngleRoll ",
"AngleYaw ",
"GyroPitch(PID) ",
"GyroRoll(PID) ",
"GyroYaw ", //5
"GyroPitch(AC) ",
"GyroRoll(AC) ",
"GyroYaw(AC) ",
"AccPitch (angle)",
"AccRoll (angle) ", //10
"UBat ",
"Pitch Term ",
"Roll Term ",
"Yaw Term ",
"Throttle Term ", //15
"0th O Corr pitch",
"0th O Corr roll ",
"DriftCompDelta P",
"DriftCompDelta R",
"ADPitchGyroOffs ", //20
"ADRollGyroOffs ",
"M1 ",
"M2 ",
"M3 ",
"M4 ", //25
"ControlYaw ",
"Airpress. Range ",
"DriftCompPitch ",
"DriftCompRoll ",
"AirpressFiltered", //30
"AirpressADC "
};
//1234567890123456
"AnglePitch ", //0
"AngleRoll ",
"AngleYaw ",
"GyroPitch(PID) ",
"GyroRoll(PID) ",
"GyroYaw ", //5
"GyroPitch(AC) ",
"GyroRoll(AC) ",
"GyroYaw(AC) ",
"AccPitch (angle)",
"AccRoll (angle) ", //10
"UBat ",
"Pitch Term ",
"Roll Term ",
"Yaw Term ",
"Throttle Term ", //15
"0th O Corr pitch", "0th O Corr roll ",
"DriftCompDelta P",
"DriftCompDelta R",
"ADPitchGyroOffs ", //20
"ADRollGyroOffs ", "M1 ", "M2 ",
"M3 ",
"M4 ", //25
"ControlYaw ", "Airpress. Range ", "DriftCompPitch ",
"DriftCompRoll ", "AirpressFiltered", //30
"AirpressADC " };
 
/****************************************************************/
/* Initialization of the USART0 */
/****************************************************************/
void usart0_Init (void) {
uint8_t sreg = SREG;
uint16_t ubrr = (uint16_t) ((uint32_t) SYSCLK/(8 * USART0_BAUD) - 1);
// disable all interrupts before configuration
cli();
// disable RX-Interrupt
UCSR0B &= ~(1 << RXCIE0);
// disable TX-Interrupt
UCSR0B &= ~(1 << TXCIE0);
// set direction of RXD0 and TXD0 pins
// set RXD0 (PD0) as an input pin
PORTD |= (1 << PORTD0);
DDRD &= ~(1 << DDD0);
// set TXD0 (PD1) as an output pin
PORTD |= (1 << PORTD1);
DDRD |= (1 << DDD1);
// USART0 Baud Rate Register
// set clock divider
UBRR0H = (uint8_t)(ubrr >> 8);
UBRR0L = (uint8_t)ubrr;
// USART0 Control and Status Register A, B, C
// enable double speed operation in
UCSR0A |= (1 << U2X0);
// enable receiver and transmitter in
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
// set asynchronous mode
UCSR0C &= ~(1 << UMSEL01);
UCSR0C &= ~(1 << UMSEL00);
// no parity
UCSR0C &= ~(1 << UPM01);
UCSR0C &= ~(1 << UPM00);
// 1 stop bit
UCSR0C &= ~(1 << USBS0);
// 8-bit
UCSR0B &= ~(1 << UCSZ02);
UCSR0C |= (1 << UCSZ01);
UCSR0C |= (1 << UCSZ00);
// flush receive buffer
while ( UCSR0A & (1<<RXC0) ) UDR0;
// enable interrupts at the end
// enable RX-Interrupt
UCSR0B |= (1 << RXCIE0);
// enable TX-Interrupt
UCSR0B |= (1 << TXCIE0);
// initialize the debug timer
DebugData_Timer = SetDelay(DebugData_Interval);
// unlock rxd_buffer
rxd_buffer_locked = FALSE;
pRxData = 0;
RxDataLen = 0;
// no bytes to send
txd_complete = TRUE;
void usart0_Init(void) {
uint8_t sreg = SREG;
uint16_t ubrr = (uint16_t) ((uint32_t) SYSCLK / (8 * USART0_BAUD) - 1);
 
// disable all interrupts before configuration
cli();
 
// disable RX-Interrupt
UCSR0B &= ~(1 << RXCIE0);
// disable TX-Interrupt
UCSR0B &= ~(1 << TXCIE0);
 
// set direction of RXD0 and TXD0 pins
// set RXD0 (PD0) as an input pin
PORTD |= (1 << PORTD0);
DDRD &= ~(1 << DDD0);
// set TXD0 (PD1) as an output pin
PORTD |= (1 << PORTD1);
DDRD |= (1 << DDD1);
 
// USART0 Baud Rate Register
// set clock divider
UBRR0H = (uint8_t) (ubrr >> 8);
UBRR0L = (uint8_t) ubrr;
 
// USART0 Control and Status Register A, B, C
 
// enable double speed operation in
UCSR0A |= (1 << U2X0);
// enable receiver and transmitter in
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
// set asynchronous mode
UCSR0C &= ~(1 << UMSEL01);
UCSR0C &= ~(1 << UMSEL00);
// no parity
UCSR0C &= ~(1 << UPM01);
UCSR0C &= ~(1 << UPM00);
// 1 stop bit
UCSR0C &= ~(1 << USBS0);
// 8-bit
UCSR0B &= ~(1 << UCSZ02);
UCSR0C |= (1 << UCSZ01);
UCSR0C |= (1 << UCSZ00);
 
// flush receive buffer
while (UCSR0A & (1 << RXC0))
UDR0;
 
// enable interrupts at the end
// enable RX-Interrupt
UCSR0B |= (1 << RXCIE0);
// enable TX-Interrupt
UCSR0B |= (1 << TXCIE0);
 
// initialize the debug timer
DebugData_Timer = SetDelay(DebugData_Interval);
 
// unlock rxd_buffer
rxd_buffer_locked = FALSE;
pRxData = 0;
RxDataLen = 0;
 
// no bytes to send
txd_complete = TRUE;
 
#ifdef USE_MK3MAG
Compass_Timer = SetDelay(220);
Compass_Timer = SetDelay(220);
#endif
UART_VersionInfo.SWMajor = VERSION_MAJOR;
UART_VersionInfo.SWMinor = VERSION_MINOR;
UART_VersionInfo.SWPatch = VERSION_PATCH;
UART_VersionInfo.ProtoMajor = VERSION_SERIAL_MAJOR;
UART_VersionInfo.ProtoMinor = VERSION_SERIAL_MINOR;
// restore global interrupt flags
SREG = sreg;
 
UART_VersionInfo.SWMajor = VERSION_MAJOR;
UART_VersionInfo.SWMinor = VERSION_MINOR;
UART_VersionInfo.SWPatch = VERSION_PATCH;
UART_VersionInfo.ProtoMajor = VERSION_SERIAL_MAJOR;
UART_VersionInfo.ProtoMinor = VERSION_SERIAL_MINOR;
 
// restore global interrupt flags
SREG = sreg;
}
 
/****************************************************************/
/* USART0 transmitter ISR */
/****************************************************************/
ISR(USART0_TX_vect) {
static uint16_t ptr_txd_buffer = 0;
uint8_t tmp_tx;
if(!txd_complete) { // transmission not completed
ptr_txd_buffer++; // die [0] wurde schon gesendet
tmp_tx = txd_buffer[ptr_txd_buffer];
// if terminating character or end of txd buffer was reached
if((tmp_tx == '\r') || (ptr_txd_buffer == TXD_BUFFER_LEN)) {
ptr_txd_buffer = 0; // reset txd pointer
txd_complete = 1; // stop transmission
}
UDR0 = tmp_tx; // send current byte will trigger this ISR again
}
// transmission completed
else ptr_txd_buffer = 0;
ISR(USART0_TX_vect)
{
static uint16_t ptr_txd_buffer = 0;
uint8_t tmp_tx;
if (!txd_complete) { // transmission not completed
ptr_txd_buffer++; // die [0] wurde schon gesendet
tmp_tx = txd_buffer[ptr_txd_buffer];
// if terminating character or end of txd buffer was reached
if ((tmp_tx == '\r') || (ptr_txd_buffer == TXD_BUFFER_LEN)) {
ptr_txd_buffer = 0; // reset txd pointer
txd_complete = 1; // stop transmission
}
UDR0 = tmp_tx; // send current byte will trigger this ISR again
}
// transmission completed
else
ptr_txd_buffer = 0;
}
 
/****************************************************************/
/* USART0 receiver ISR */
/****************************************************************/
ISR(USART0_RX_vect) {
static uint16_t crc;
static uint8_t ptr_rxd_buffer = 0;
uint8_t crc1, crc2;
uint8_t c;
ISR(USART0_RX_vect)
{
static uint16_t crc;
static uint8_t ptr_rxd_buffer = 0;
uint8_t crc1, crc2;
uint8_t c;
 
c = UDR0; // catch the received byte
c = UDR0; // catch the received byte
 
if(rxd_buffer_locked) return; // if rxd buffer is locked immediately return
if (rxd_buffer_locked)
return; // if rxd buffer is locked immediately return
 
// the rxd buffer is unlocked
if((ptr_rxd_buffer == 0) && (c == '#')) { // if rxd buffer is empty and syncronisation character is received
rxd_buffer[ptr_rxd_buffer++] = c; // copy 1st byte to buffer
crc = c; // init crc
}
// the rxd buffer is unlocked
if ((ptr_rxd_buffer == 0) && (c == '#')) { // if rxd buffer is empty and syncronisation character is received
rxd_buffer[ptr_rxd_buffer++] = c; // copy 1st byte to buffer
crc = c; // init crc
}
#if 0
else if (ptr_rxd_buffer == 1) { // handle address
rxd_buffer[ptr_rxd_buffer++] = c; // copy byte to rxd buffer
crc += c; // update crc
}
else if (ptr_rxd_buffer == 1) { // handle address
rxd_buffer[ptr_rxd_buffer++] = c; // copy byte to rxd buffer
crc += c; // update crc
}
#endif
else if (ptr_rxd_buffer < RXD_BUFFER_LEN) { // collect incomming bytes
if(c != '\r') { // no termination character
rxd_buffer[ptr_rxd_buffer++] = c; // copy byte to rxd buffer
crc += c; // update crc
} else { // termination character was received
// the last 2 bytes are no subject for checksum calculation
// they are the checksum itself
crc -= rxd_buffer[ptr_rxd_buffer-2];
crc -= rxd_buffer[ptr_rxd_buffer-1];
// calculate checksum from transmitted data
crc %= 4096;
crc1 = '=' + crc / 64;
crc2 = '=' + crc % 64;
// compare checksum to transmitted checksum bytes
if((crc1 == rxd_buffer[ptr_rxd_buffer-2]) && (crc2 == rxd_buffer[ptr_rxd_buffer-1])) {
// checksum valid
rxd_buffer[ptr_rxd_buffer] = '\r'; // set termination character
ReceivedBytes = ptr_rxd_buffer + 1;// store number of received bytes
rxd_buffer_locked = TRUE; // lock the rxd buffer
// if 2nd byte is an 'R' enable watchdog that will result in an reset
if(rxd_buffer[2] == 'R') {wdt_enable(WDTO_250MS);} // Reset-Commando
} else { // checksum invalid
rxd_buffer_locked = FALSE; // unlock rxd buffer
}
ptr_rxd_buffer = 0; // reset rxd buffer pointer
}
} else { // rxd buffer overrun
ptr_rxd_buffer = 0; // reset rxd buffer
rxd_buffer_locked = FALSE; // unlock rxd buffer
}
else if (ptr_rxd_buffer < RXD_BUFFER_LEN) { // collect incomming bytes
if (c != '\r') { // no termination character
rxd_buffer[ptr_rxd_buffer++] = c; // copy byte to rxd buffer
crc += c; // update crc
} else { // termination character was received
// the last 2 bytes are no subject for checksum calculation
// they are the checksum itself
crc -= rxd_buffer[ptr_rxd_buffer - 2];
crc -= rxd_buffer[ptr_rxd_buffer - 1];
// calculate checksum from transmitted data
crc %= 4096;
crc1 = '=' + crc / 64;
crc2 = '=' + crc % 64;
// compare checksum to transmitted checksum bytes
if ((crc1 == rxd_buffer[ptr_rxd_buffer - 2]) && (crc2
== rxd_buffer[ptr_rxd_buffer - 1])) {
// checksum valid
rxd_buffer[ptr_rxd_buffer] = '\r'; // set termination character
ReceivedBytes = ptr_rxd_buffer + 1;// store number of received bytes
rxd_buffer_locked = TRUE; // lock the rxd buffer
// if 2nd byte is an 'R' enable watchdog that will result in an reset
if (rxd_buffer[2] == 'R') {
wdt_enable(WDTO_250MS);
} // Reset-Commando
} else { // checksum invalid
rxd_buffer_locked = FALSE; // unlock rxd buffer
}
ptr_rxd_buffer = 0; // reset rxd buffer pointer
}
} else { // rxd buffer overrun
ptr_rxd_buffer = 0; // reset rxd buffer
rxd_buffer_locked = FALSE; // unlock rxd buffer
}
}
 
// --------------------------------------------------------------------------
void AddCRC(uint16_t datalen) {
uint16_t tmpCRC = 0, i;
for(i = 0; i < datalen; i++) {
tmpCRC += txd_buffer[i];
}
tmpCRC %= 4096;
txd_buffer[i++] = '=' + tmpCRC / 64;
txd_buffer[i++] = '=' + tmpCRC % 64;
txd_buffer[i++] = '\r';
txd_complete = FALSE;
UDR0 = txd_buffer[0]; // initiates the transmittion (continued in the TXD ISR)
uint16_t tmpCRC = 0, i;
for (i = 0; i < datalen; i++) {
tmpCRC += txd_buffer[i];
}
tmpCRC %= 4096;
txd_buffer[i++] = '=' + tmpCRC / 64;
txd_buffer[i++] = '=' + tmpCRC % 64;
txd_buffer[i++] = '\r';
txd_complete = FALSE;
UDR0 = txd_buffer[0]; // initiates the transmittion (continued in the TXD ISR)
}
 
// --------------------------------------------------------------------------
331,393 → 332,428
// application example:
// SendOutData('A', FC_ADDRESS, 2, (uint8_t *)&request_DebugLabel, sizeof(request_DebugLabel), label, 16);
/*
void SendOutData(uint8_t cmd, uint8_t addr, uint8_t numofbuffers, ...) { // uint8_t *pdata, uint8_t len, ...
va_list ap;
uint16_t txd_bufferIndex = 0;
uint8_t *currentBuffer;
uint8_t currentBufferIndex;
uint16_t lengthOfCurrentBuffer;
uint8_t shift = 0;
txd_buffer[txd_bufferIndex++] = '#'; // Start character
txd_buffer[txd_bufferIndex++] = 'a' + addr; // Address (a=0; b=1,...)
txd_buffer[txd_bufferIndex++] = cmd; // Command
va_start(ap, numofbuffers);
void SendOutData(uint8_t cmd, uint8_t addr, uint8_t numofbuffers, ...) { // uint8_t *pdata, uint8_t len, ...
va_list ap;
uint16_t txd_bufferIndex = 0;
uint8_t *currentBuffer;
uint8_t currentBufferIndex;
uint16_t lengthOfCurrentBuffer;
uint8_t shift = 0;
 
while(numofbuffers) {
currentBuffer = va_arg(ap, uint8_t*);
lengthOfCurrentBuffer = va_arg(ap, int);
currentBufferIndex = 0;
// Encode data: 3 bytes of data are encoded into 4 bytes,
// where the 2 most significant bits are both 0.
while(currentBufferIndex != lengthOfCurrentBuffer) {
if (!shift) txd_buffer[txd_bufferIndex] = 0;
txd_buffer[txd_bufferIndex] |= currentBuffer[currentBufferIndex] >> (shift + 2);
txd_buffer[++txd_bufferIndex] = (currentBuffer[currentBufferIndex] << (4 - shift)) & 0b00111111;
shift += 2;
if (shift == 6) { shift=0; txd_bufferIndex++; }
currentBufferIndex++;
}
}
// If the number of data bytes was not divisible by 3, stuff
// with 0 pseudodata until length is again divisible by 3.
if (shift == 2) {
// We need to stuff with zero bytes at the end.
txd_buffer[txd_bufferIndex] &= 0b00110000;
txd_buffer[++txd_bufferIndex] = 0;
shift = 4;
}
if (shift == 4) {
// We need to stuff with zero bytes at the end.
txd_buffer[txd_bufferIndex++] &= 0b00111100;
txd_buffer[txd_bufferIndex] = 0;
}
va_end(ap);
AddCRC(pt); // add checksum after data block and initates the transmission
}
*/
txd_buffer[txd_bufferIndex++] = '#'; // Start character
txd_buffer[txd_bufferIndex++] = 'a' + addr; // Address (a=0; b=1,...)
txd_buffer[txd_bufferIndex++] = cmd; // Command
 
va_start(ap, numofbuffers);
 
while(numofbuffers) {
currentBuffer = va_arg(ap, uint8_t*);
lengthOfCurrentBuffer = va_arg(ap, int);
currentBufferIndex = 0;
// Encode data: 3 bytes of data are encoded into 4 bytes,
// where the 2 most significant bits are both 0.
while(currentBufferIndex != lengthOfCurrentBuffer) {
if (!shift) txd_buffer[txd_bufferIndex] = 0;
txd_buffer[txd_bufferIndex] |= currentBuffer[currentBufferIndex] >> (shift + 2);
txd_buffer[++txd_bufferIndex] = (currentBuffer[currentBufferIndex] << (4 - shift)) & 0b00111111;
shift += 2;
if (shift == 6) { shift=0; txd_bufferIndex++; }
currentBufferIndex++;
}
}
// If the number of data bytes was not divisible by 3, stuff
// with 0 pseudodata until length is again divisible by 3.
if (shift == 2) {
// We need to stuff with zero bytes at the end.
txd_buffer[txd_bufferIndex] &= 0b00110000;
txd_buffer[++txd_bufferIndex] = 0;
shift = 4;
}
if (shift == 4) {
// We need to stuff with zero bytes at the end.
txd_buffer[txd_bufferIndex++] &= 0b00111100;
txd_buffer[txd_bufferIndex] = 0;
}
va_end(ap);
AddCRC(pt); // add checksum after data block and initates the transmission
}
*/
 
void SendOutData(uint8_t cmd, uint8_t addr, uint8_t numofbuffers, ...) { // uint8_t *pdata, uint8_t len, ...
va_list ap;
uint16_t pt = 0;
uint8_t a,b,c;
uint8_t ptr = 0;
uint8_t *pdata = 0;
int len = 0;
txd_buffer[pt++] = '#'; // Start character
txd_buffer[pt++] = 'a' + addr; // Address (a=0; b=1,...)
txd_buffer[pt++] = cmd; // Command
va_start(ap, numofbuffers);
va_list ap;
uint16_t pt = 0;
uint8_t a, b, c;
uint8_t ptr = 0;
 
if(numofbuffers) {
pdata = va_arg(ap, uint8_t*);
len = va_arg(ap, int);
ptr = 0;
numofbuffers--;
}
uint8_t *pdata = 0;
int len = 0;
 
while(len){
if(len) {
a = pdata[ptr++];
len--;
if((!len) && numofbuffers) {
pdata = va_arg(ap, uint8_t*);
len = va_arg(ap, int);
ptr = 0;
numofbuffers--;
}
}
else a = 0;
if(len) {
b = pdata[ptr++];
len--;
if((!len) && numofbuffers) {
pdata = va_arg(ap, uint8_t*);
len = va_arg(ap, int);
ptr = 0;
numofbuffers--;
}
} else b = 0;
if(len) {
c = pdata[ptr++];
len--;
if((!len) && numofbuffers) {
pdata = va_arg(ap, uint8_t*);
len = va_arg(ap, int);
ptr = 0;
numofbuffers--;
}
}
else c = 0;
txd_buffer[pt++] = '=' + (a >> 2);
txd_buffer[pt++] = '=' + (((a & 0x03) << 4) | ((b & 0xf0) >> 4));
txd_buffer[pt++] = '=' + (((b & 0x0f) << 2) | ((c & 0xc0) >> 6));
txd_buffer[pt++] = '=' + ( c & 0x3f);
}
va_end(ap);
AddCRC(pt); // add checksum after data block and initates the transmission
txd_buffer[pt++] = '#'; // Start character
txd_buffer[pt++] = 'a' + addr; // Address (a=0; b=1,...)
txd_buffer[pt++] = cmd; // Command
 
va_start(ap, numofbuffers);
 
if (numofbuffers) {
pdata = va_arg(ap, uint8_t*);
len = va_arg(ap, int);
ptr = 0;
numofbuffers--;
}
 
while (len) {
if (len) {
a = pdata[ptr++];
len--;
if ((!len) && numofbuffers) {
pdata = va_arg(ap, uint8_t*);
len = va_arg(ap, int);
ptr = 0;
numofbuffers--;
}
} else
a = 0;
if (len) {
b = pdata[ptr++];
len--;
if ((!len) && numofbuffers) {
pdata = va_arg(ap, uint8_t*);
len = va_arg(ap, int);
ptr = 0;
numofbuffers--;
}
} else
b = 0;
if (len) {
c = pdata[ptr++];
len--;
if ((!len) && numofbuffers) {
pdata = va_arg(ap, uint8_t*);
len = va_arg(ap, int);
ptr = 0;
numofbuffers--;
}
} else
c = 0;
txd_buffer[pt++] = '=' + (a >> 2);
txd_buffer[pt++] = '=' + (((a & 0x03) << 4) | ((b & 0xf0) >> 4));
txd_buffer[pt++] = '=' + (((b & 0x0f) << 2) | ((c & 0xc0) >> 6));
txd_buffer[pt++] = '=' + (c & 0x3f);
}
va_end(ap);
AddCRC(pt); // add checksum after data block and initates the transmission
}
 
// --------------------------------------------------------------------------
void Decode64(void) {
uint8_t a,b,c,d;
uint8_t x,y,z;
uint8_t ptrIn = 3;
uint8_t ptrOut = 3;
uint8_t len = ReceivedBytes - 6;
while(len) {
a = rxd_buffer[ptrIn++] - '=';
b = rxd_buffer[ptrIn++] - '=';
c = rxd_buffer[ptrIn++] - '=';
d = rxd_buffer[ptrIn++] - '=';
//if(ptrIn > ReceivedBytes - 3) break;
x = (a << 2) | (b >> 4);
y = ((b & 0x0f) << 4) | (c >> 2);
z = ((c & 0x03) << 6) | d;
if(len--) rxd_buffer[ptrOut++] = x; else break;
if(len--) rxd_buffer[ptrOut++] = y; else break;
if(len--) rxd_buffer[ptrOut++] = z; else break;
}
pRxData = &rxd_buffer[3];
RxDataLen = ptrOut - 3;
uint8_t a, b, c, d;
uint8_t x, y, z;
uint8_t ptrIn = 3;
uint8_t ptrOut = 3;
uint8_t len = ReceivedBytes - 6;
 
while (len) {
a = rxd_buffer[ptrIn++] - '=';
b = rxd_buffer[ptrIn++] - '=';
c = rxd_buffer[ptrIn++] - '=';
d = rxd_buffer[ptrIn++] - '=';
//if(ptrIn > ReceivedBytes - 3) break;
 
x = (a << 2) | (b >> 4);
y = ((b & 0x0f) << 4) | (c >> 2);
z = ((c & 0x03) << 6) | d;
 
if (len--)
rxd_buffer[ptrOut++] = x;
else
break;
if (len--)
rxd_buffer[ptrOut++] = y;
else
break;
if (len--)
rxd_buffer[ptrOut++] = z;
else
break;
}
pRxData = &rxd_buffer[3];
RxDataLen = ptrOut - 3;
}
 
// --------------------------------------------------------------------------
void usart0_ProcessRxData(void) {
// We control the motorTestActive var from here: Count it down.
if (motorTestActive) motorTestActive--;
// if data in the rxd buffer are not locked immediately return
if(!rxd_buffer_locked) return;
uint8_t tempchar1, tempchar2;
Decode64(); // decode data block in rxd_buffer
// We control the motorTestActive var from here: Count it down.
if (motorTestActive)
motorTestActive--;
// if data in the rxd buffer are not locked immediately return
if (!rxd_buffer_locked)
return;
uint8_t tempchar1, tempchar2;
Decode64(); // decode data block in rxd_buffer
 
switch(rxd_buffer[1] - 'a') {
switch (rxd_buffer[1] - 'a') {
 
case FC_ADDRESS:
switch(rxd_buffer[2]) {
case FC_ADDRESS:
switch (rxd_buffer[2]) {
#ifdef USE_MK3MAG
case 'K':// compass value
compassHeading = ((Heading_t *)pRxData)->Heading;
compassOffCourse = ((540 + compassHeading - compassCourse) % 360) - 180;
break;
case 'K':// compass value
compassHeading = ((Heading_t *)pRxData)->Heading;
// compassOffCourse = ((540 + compassHeading - compassCourse) % 360) - 180;
break;
#endif
case 't': // motor test
if(RxDataLen > 20) {
memcpy(&motorTest[0], (uint8_t*)pRxData, sizeof(motorTest));
} else {
memcpy(&motorTest[0], (uint8_t*)pRxData, 4);
}
motorTestActive = 255;
externalControlActive = 255;
break;
case 'n':// "Get Mixer Table
while(!txd_complete); // wait for previous frame to be sent
SendOutData('N', FC_ADDRESS, 1, (uint8_t *) &Mixer, sizeof(Mixer));
break;
case 't': // motor test
if (RxDataLen > 20) {
memcpy(&motorTest[0], (uint8_t*) pRxData, sizeof(motorTest));
} else {
memcpy(&motorTest[0], (uint8_t*) pRxData, 4);
}
motorTestActive = 255;
externalControlActive = 255;
break;
 
case 'm':// "Set Mixer Table
if(pRxData[0] == EEMIXER_REVISION) {
memcpy(&Mixer, (uint8_t*)pRxData, sizeof(Mixer));
MixerTable_WriteToEEProm();
while(!txd_complete); // wait for previous frame to be sent
tempchar1 = 1;
} else {
tempchar1 = 0;
}
SendOutData('M', FC_ADDRESS, 1, &tempchar1, 1);
break;
case 'n':// "Get Mixer Table
while (!txd_complete)
; // wait for previous frame to be sent
SendOutData('N', FC_ADDRESS, 1, (uint8_t *) &Mixer, sizeof(Mixer));
break;
 
case 'p': // get PPM channels
request_PPMChannels = TRUE;
break;
case 'm':// "Set Mixer Table
if (pRxData[0] == EEMIXER_REVISION) {
memcpy(&Mixer, (uint8_t*) pRxData, sizeof(Mixer));
MixerTable_WriteToEEProm();
while (!txd_complete)
; // wait for previous frame to be sent
tempchar1 = 1;
} else {
tempchar1 = 0;
}
SendOutData('M', FC_ADDRESS, 1, &tempchar1, 1);
break;
 
case 'q':// request settings
if(pRxData[0] == 0xFF) {
pRxData[0] = GetParamByte(PID_ACTIVE_SET);
}
// limit settings range
if(pRxData[0] < 1) pRxData[0] = 1; // limit to 1
else if(pRxData[0] > 5) pRxData[0] = 5; // limit to 5
// load requested parameter set
ParamSet_ReadFromEEProm(pRxData[0]);
tempchar1 = pRxData[0];
tempchar2 = EEPARAM_REVISION;
while(!txd_complete); // wait for previous frame to be sent
SendOutData('Q', FC_ADDRESS,3, &tempchar1, sizeof(tempchar1), &tempchar2, sizeof(tempchar2), (uint8_t *) &staticParams, sizeof(staticParams));
break;
case 'p': // get PPM channels
request_PPMChannels = TRUE;
break;
 
case 's': // save settings
if(!(MKFlags & MKFLAG_MOTOR_RUN)) // save settings only if motors ar off
{
if((1 <= pRxData[0]) && (pRxData[0] <= 5) && (pRxData[1] == EEPARAM_REVISION)) // check for setting to be in range and version of settings
{
memcpy(&staticParams, (uint8_t*)&pRxData[2], sizeof(staticParams));
ParamSet_WriteToEEProm(pRxData[0]);
/*
TODO: Remove this encapsulation breach
turnOver180Pitch = (int32_t) staticParams.AngleTurnOverPitch * 2500L;
turnOver180Roll = (int32_t) staticParams.AngleTurnOverRoll * 2500L;
*/
tempchar1 = getActiveParamSet();
beepNumber(tempchar1);
}
else
{
tempchar1 = 0; //indicate bad data
}
while(!txd_complete); // wait for previous frame to be sent
SendOutData('S', FC_ADDRESS,1, &tempchar1, sizeof(tempchar1));
}
break;
case 'q':// request settings
if (pRxData[0] == 0xFF) {
pRxData[0] = GetParamByte(PID_ACTIVE_SET);
}
// limit settings range
if (pRxData[0] < 1)
pRxData[0] = 1; // limit to 1
else if (pRxData[0] > 5)
pRxData[0] = 5; // limit to 5
// load requested parameter set
ParamSet_ReadFromEEProm(pRxData[0]);
tempchar1 = pRxData[0];
tempchar2 = EEPARAM_REVISION;
while (!txd_complete)
; // wait for previous frame to be sent
SendOutData('Q', FC_ADDRESS, 3, &tempchar1, sizeof(tempchar1),
&tempchar2, sizeof(tempchar2), (uint8_t *) &staticParams,
sizeof(staticParams));
break;
 
default:
//unsupported command received
break;
} // case FC_ADDRESS:
case 's': // save settings
if (!(MKFlags & MKFLAG_MOTOR_RUN)) // save settings only if motors are off
{
if ((1 <= pRxData[0]) && (pRxData[0] <= 5) && (pRxData[1]
== EEPARAM_REVISION)) // check for setting to be in range and version of settings
{
memcpy(&staticParams, (uint8_t*) &pRxData[2], sizeof(staticParams));
ParamSet_WriteToEEProm(pRxData[0]);
/*
TODO: Remove this encapsulation breach
turnOver180Pitch = (int32_t) staticParams.AngleTurnOverPitch * 2500L;
turnOver180Roll = (int32_t) staticParams.AngleTurnOverRoll * 2500L;
*/
tempchar1 = getActiveParamSet();
beepNumber(tempchar1);
} else {
tempchar1 = 0; //indicate bad data
}
while (!txd_complete)
; // wait for previous frame to be sent
SendOutData('S', FC_ADDRESS, 1, &tempchar1, sizeof(tempchar1));
}
break;
 
default: // any Slave Address
switch(rxd_buffer[2]) {
case 'a':// request for labels of the analog debug outputs
request_DebugLabel = pRxData[0];
if(request_DebugLabel > 31) request_DebugLabel = 31;
externalControlActive = 255;
break;
default:
//unsupported command received
break;
} // case FC_ADDRESS:
 
case 'b': // submit extern control
memcpy(&externalControl, (uint8_t*)pRxData, sizeof(externalControl));
ConfirmFrame = externalControl.frame;
externalControlActive = 255;
break;
default: // any Slave Address
switch (rxd_buffer[2]) {
case 'a':// request for labels of the analog debug outputs
request_DebugLabel = pRxData[0];
if (request_DebugLabel > 31)
request_DebugLabel = 31;
externalControlActive = 255;
break;
 
case 'h':// request for display columns
externalControlActive = 255;
RemoteKeys |= pRxData[0];
if(RemoteKeys) DisplayLine = 0;
request_Display = TRUE;
break;
case 'b': // submit extern control
memcpy(&externalControl, (uint8_t*) pRxData, sizeof(externalControl));
ConfirmFrame = externalControl.frame;
externalControlActive = 255;
break;
 
case 'l':// request for display columns
externalControlActive = 255;
MenuItem = pRxData[0];
request_Display1 = TRUE;
break;
case 'h':// request for display columns
externalControlActive = 255;
RemoteKeys |= pRxData[0];
if (RemoteKeys)
DisplayLine = 0;
request_Display = TRUE;
break;
 
case 'v': // request for version and board release
request_VerInfo = TRUE;
break;
case 'l':// request for display columns
externalControlActive = 255;
MenuItem = pRxData[0];
request_Display1 = TRUE;
break;
 
case 'x':
request_variables = TRUE;
break;
case 'v': // request for version and board release
request_VerInfo = TRUE;
break;
 
case 'g':// get external control data
request_ExternalControl = TRUE;
break;
case 'x':
request_variables = TRUE;
break;
 
case 'd': // request for the debug data
DebugData_Interval = (uint16_t) pRxData[0] * 10;
if(DebugData_Interval > 0) request_DebugData = TRUE;
break;
case 'g':// get external control data
request_ExternalControl = TRUE;
break;
 
case 'c': // request for the 3D data
Data3D_Interval = (uint16_t) pRxData[0] * 10;
if(Data3D_Interval > 0) request_Data3D = TRUE;
break;
case 'd': // request for the debug data
DebugData_Interval = (uint16_t) pRxData[0] * 10;
if (DebugData_Interval > 0)
request_DebugData = TRUE;
break;
 
default:
//unsupported command received
break;
}
break; // default:
}
// unlock the rxd buffer after processing
pRxData = 0;
RxDataLen = 0;
rxd_buffer_locked = FALSE;
case 'c': // request for the 3D data
Data3D_Interval = (uint16_t) pRxData[0] * 10;
if (Data3D_Interval > 0)
request_Data3D = TRUE;
break;
 
default:
//unsupported command received
break;
}
break; // default:
}
// unlock the rxd buffer after processing
pRxData = 0;
RxDataLen = 0;
rxd_buffer_locked = FALSE;
}
 
/************************************************************************/
/* Routine für die Serielle Ausgabe */
/************************************************************************/
int16_t uart_putchar (int8_t c) {
if (c == '\n')
uart_putchar('\r');
// wait until previous character was send
loop_until_bit_is_set(UCSR0A, UDRE0);
// send character
UDR0 = c;
return (0);
int16_t uart_putchar(int8_t c) {
if (c == '\n')
uart_putchar('\r');
// wait until previous character was send
loop_until_bit_is_set(UCSR0A, UDRE0);
// send character
UDR0 = c;
return (0);
}
 
//---------------------------------------------------------------------------------------------
void usart0_TransmitTxData(void) {
if(!txd_complete) return;
if (!txd_complete)
return;
 
if(request_VerInfo && txd_complete) {
SendOutData('V', FC_ADDRESS, 1, (uint8_t *) &UART_VersionInfo, sizeof(UART_VersionInfo));
request_VerInfo = FALSE;
}
if(request_Display && txd_complete) {
LCD_PrintMenu();
SendOutData('H', FC_ADDRESS, 2, &DisplayLine, sizeof(DisplayLine), &DisplayBuff[DisplayLine * 20], 20);
DisplayLine++;
if(DisplayLine >= 4) DisplayLine = 0;
request_Display = FALSE;
}
if(request_Display1 && txd_complete) {
LCD_PrintMenu();
SendOutData('L', FC_ADDRESS, 3, &MenuItem, sizeof(MenuItem), &MaxMenuItem, sizeof(MaxMenuItem), DisplayBuff, sizeof(DisplayBuff));
request_Display1 = FALSE;
}
if(request_DebugLabel != 0xFF) { // Texte für die Analogdaten
uint8_t label[16]; // local sram buffer
memcpy_P(label, ANALOG_LABEL[request_DebugLabel], 16); // read lable from flash to sram buffer
SendOutData('A', FC_ADDRESS, 2, (uint8_t *) &request_DebugLabel, sizeof(request_DebugLabel), label, 16);
request_DebugLabel = 0xFF;
}
if(ConfirmFrame && txd_complete) { // Datensatz ohne CRC bestätigen
SendOutData('B', FC_ADDRESS, 1, (uint8_t*)&ConfirmFrame, sizeof(ConfirmFrame));
ConfirmFrame = 0;
}
if(((DebugData_Interval && CheckDelay(DebugData_Timer)) || request_DebugData) && txd_complete) {
SendOutData('D', FC_ADDRESS, 1,(uint8_t *) &DebugOut, sizeof(DebugOut));
DebugData_Timer = SetDelay(DebugData_Interval);
request_DebugData = FALSE;
}
if( ((Data3D_Interval && CheckDelay(Data3D_Timer)) || request_Data3D) && txd_complete) {
SendOutData('C', FC_ADDRESS, 1,(uint8_t *) &Data3D, sizeof(Data3D));
Data3D.AngleNick = (int16_t)((10 * angle[PITCH]) / GYRO_DEG_FACTOR_PITCHROLL); // convert to multiple of 0.1°
Data3D.AngleRoll = (int16_t)((10 * angle[ROLL]) / GYRO_DEG_FACTOR_PITCHROLL); // convert to multiple of 0.1°
Data3D.Heading = (int16_t)((10 * yawGyroHeading) / GYRO_DEG_FACTOR_YAW); // convert to multiple of 0.1°
Data3D_Timer = SetDelay(Data3D_Interval);
request_Data3D = FALSE;
}
if (request_VerInfo && txd_complete) {
SendOutData('V', FC_ADDRESS, 1, (uint8_t *) &UART_VersionInfo,
sizeof(UART_VersionInfo));
request_VerInfo = FALSE;
}
 
if(request_ExternalControl && txd_complete) {
SendOutData('G', FC_ADDRESS, 1,(uint8_t *) &externalControl, sizeof(externalControl));
request_ExternalControl = FALSE;
}
if (request_Display && txd_complete) {
LCD_PrintMenu();
SendOutData('H', FC_ADDRESS, 2, &DisplayLine, sizeof(DisplayLine),
&DisplayBuff[DisplayLine * 20], 20);
DisplayLine++;
if (DisplayLine >= 4)
DisplayLine = 0;
request_Display = FALSE;
}
 
if (request_Display1 && txd_complete) {
LCD_PrintMenu();
SendOutData('L', FC_ADDRESS, 3, &MenuItem, sizeof(MenuItem), &MaxMenuItem,
sizeof(MaxMenuItem), DisplayBuff, sizeof(DisplayBuff));
request_Display1 = FALSE;
}
 
if (request_DebugLabel != 0xFF) { // Texte für die Analogdaten
uint8_t label[16]; // local sram buffer
memcpy_P(label, ANALOG_LABEL[request_DebugLabel], 16); // read lable from flash to sram buffer
SendOutData('A', FC_ADDRESS, 2, (uint8_t *) &request_DebugLabel,
sizeof(request_DebugLabel), label, 16);
request_DebugLabel = 0xFF;
}
 
if (ConfirmFrame && txd_complete) { // Datensatz ohne CRC bestätigen
SendOutData('B', FC_ADDRESS, 1, (uint8_t*) &ConfirmFrame,
sizeof(ConfirmFrame));
ConfirmFrame = 0;
}
 
if (((DebugData_Interval && CheckDelay(DebugData_Timer)) || request_DebugData)
&& txd_complete) {
SendOutData('D', FC_ADDRESS, 1, (uint8_t *) &DebugOut, sizeof(DebugOut));
DebugData_Timer = SetDelay(DebugData_Interval);
request_DebugData = FALSE;
}
 
if (((Data3D_Interval && CheckDelay(Data3D_Timer)) || request_Data3D)
&& txd_complete) {
SendOutData('C', FC_ADDRESS, 1, (uint8_t *) &Data3D, sizeof(Data3D));
Data3D.AngleNick = (int16_t) ((10 * angle[PITCH])
/ GYRO_DEG_FACTOR_PITCHROLL); // convert to multiple of 0.1°
Data3D.AngleRoll = (int16_t) ((10 * angle[ROLL])
/ GYRO_DEG_FACTOR_PITCHROLL); // convert to multiple of 0.1°
Data3D.Heading = (int16_t) ((10 * yawGyroHeading) / GYRO_DEG_FACTOR_YAW); // convert to multiple of 0.1°
Data3D_Timer = SetDelay(Data3D_Interval);
request_Data3D = FALSE;
}
 
if (request_ExternalControl && txd_complete) {
SendOutData('G', FC_ADDRESS, 1, (uint8_t *) &externalControl,
sizeof(externalControl));
request_ExternalControl = FALSE;
}
 
#ifdef USE_MK3MAG
if((CheckDelay(Compass_Timer)) && txd_complete) {
ToMk3Mag.Attitude[0] = (int16_t)((10 * angle[PITCH]) / GYRO_DEG_FACTOR_PITCHROLL); // approx. 0.1 deg
ToMk3Mag.Attitude[1] = (int16_t)((10 * angle[ROLL]) / GYRO_DEG_FACTOR_PITCHROLL); // approx. 0.1 deg
ToMk3Mag.UserParam[0] = dynamicParams.UserParams[0];
ToMk3Mag.UserParam[1] = dynamicParams.UserParams[1];
ToMk3Mag.CalState = compassCalState;
SendOutData('w', MK3MAG_ADDRESS, 1,(uint8_t *) &ToMk3Mag,sizeof(ToMk3Mag));
// the last state is 5 and should be send only once to avoid multiple flash writing
if(compassCalState > 4) compassCalState = 0;
Compass_Timer = SetDelay(99);
}
if((CheckDelay(Compass_Timer)) && txd_complete) {
ToMk3Mag.Attitude[0] = (int16_t)((10 * angle[PITCH]) / GYRO_DEG_FACTOR_PITCHROLL); // approx. 0.1 deg
ToMk3Mag.Attitude[1] = (int16_t)((10 * angle[ROLL]) / GYRO_DEG_FACTOR_PITCHROLL); // approx. 0.1 deg
ToMk3Mag.UserParam[0] = dynamicParams.UserParams[0];
ToMk3Mag.UserParam[1] = dynamicParams.UserParams[1];
ToMk3Mag.CalState = compassCalState;
SendOutData('w', MK3MAG_ADDRESS, 1,(uint8_t *) &ToMk3Mag,sizeof(ToMk3Mag));
// the last state is 5 and should be send only once to avoid multiple flash writing
if(compassCalState > 4) compassCalState = 0;
Compass_Timer = SetDelay(99);
}
#endif
if(request_MotorTest && txd_complete) {
SendOutData('T', FC_ADDRESS, 0);
request_MotorTest = FALSE;
}
 
if(request_PPMChannels && txd_complete) {
SendOutData('P', FC_ADDRESS, 1, (uint8_t *)&PPM_in, sizeof(PPM_in));
request_PPMChannels = FALSE;
}
if (request_MotorTest && txd_complete) {
SendOutData('T', FC_ADDRESS, 0);
request_MotorTest = FALSE;
}
 
if (request_variables && txd_complete) {
SendOutData('X', FC_ADDRESS, 1, (uint8_t *)&variables, sizeof(variables));
request_variables = FALSE;
}
if (request_PPMChannels && txd_complete) {
SendOutData('P', FC_ADDRESS, 1, (uint8_t *) &PPM_in, sizeof(PPM_in));
request_PPMChannels = FALSE;
}
 
if (request_variables && txd_complete) {
SendOutData('X', FC_ADDRESS, 1, (uint8_t *) &variables, sizeof(variables));
request_variables = FALSE;
}
}
/branches/dongfang_FC_rewrite/uart0.h
11,7 → 11,7
//Baud rate of the USART
#define USART0_BAUD 57600
 
extern void usart0_Init (void);
extern void usart0_Init(void);
extern void usart0_TransmitTxData(void);
extern void usart0_ProcessRxData(void);
extern int16_t uart_putchar(int8_t c);
22,26 → 22,26
extern uint8_t motorTest[16];
 
typedef struct {
uint8_t Digital[2];
uint16_t Analog[32]; // Debugvalues
} __attribute__((packed)) DebugOut_t;
uint8_t Digital[2];
uint16_t Analog[32]; // Debugvalues
}__attribute__((packed)) DebugOut_t;
 
extern DebugOut_t DebugOut;
 
typedef struct {
int16_t AngleNick; // in 0.1 deg
int16_t AngleRoll; // in 0.1 deg
int16_t Heading; // in 0.1 deg
uint8_t reserve[8];
} __attribute__((packed)) Data3D_t;
int16_t AngleNick; // in 0.1 deg
int16_t AngleRoll; // in 0.1 deg
int16_t Heading; // in 0.1 deg
uint8_t reserve[8];
}__attribute__((packed)) Data3D_t;
 
typedef struct {
uint8_t SWMajor;
uint8_t SWMinor;
uint8_t ProtoMajor;
uint8_t ProtoMinor;
uint8_t SWPatch;
uint8_t Reserved[5];
} __attribute__((packed)) UART_VersionInfo_t;
uint8_t SWMajor;
uint8_t SWMinor;
uint8_t ProtoMajor;
uint8_t ProtoMinor;
uint8_t SWPatch;
uint8_t Reserved[5];
}__attribute__((packed)) UART_VersionInfo_t;
 
#endif //_UART0_H
/branches/dongfang_FC_rewrite/uart1.c
69,10 → 69,10
/****************************************************************/
/* Initialization of the USART1 */
/****************************************************************/
void usart1_Init (void) {
void usart1_Init(void) {
// USART1 Control and Status Register A, B, C and baud rate register
uint8_t sreg = SREG;
uint16_t ubrr = (uint16_t) ((uint32_t) SYSCLK/(8 * USART1_BAUD) - 1);
uint16_t ubrr = (uint16_t) ((uint32_t) SYSCLK / (8 * USART1_BAUD) - 1);
 
// disable all interrupts before reconfiguration
cli();
91,12 → 91,12
 
// set TXD1 (PD3) as an output pin
PORTD |= (1 << PORTD3);
DDRD |= (1 << DDD3);
DDRD |= (1 << DDD3);
 
// USART0 Baud Rate Register
// set clock divider
UBRR1H = (uint8_t)(ubrr>>8);
UBRR1L = (uint8_t)ubrr;
UBRR1H = (uint8_t) (ubrr >> 8);
UBRR1L = (uint8_t) ubrr;
 
// enable double speed operation
UCSR1A |= (1 << U2X1);
112,11 → 112,12
UCSR1C &= ~(1 << USBS1);
// 8-bit
UCSR1B &= ~(1 << UCSZ12);
UCSR1C |= (1 << UCSZ11);
UCSR1C |= (1 << UCSZ10);
UCSR1C |= (1 << UCSZ11);
UCSR1C |= (1 << UCSZ10);
 
// flush receive buffer explicit
while ( UCSR1A & (1<<RXC1) ) UDR1;
while (UCSR1A & (1 << RXC1))
UDR1;
 
// enable interrupts at the end
// enable RX-Interrupt
127,7 → 128,7
//UCSR1B |= (1 << UDRIE1);
 
// restore global interrupt flags
SREG = sreg;
SREG = sreg;
}
 
/****************************************************************/
134,25 → 135,26
/* USART1 data register empty ISR */
/****************************************************************/
/*ISR(USART1_UDRE_vect) {
}
*/
}
*/
 
/****************************************************************/
/* USART1 transmitter ISR */
/****************************************************************/
/*ISR(USART1_TX_vect) {
}
*/
}
*/
/****************************************************************/
/* USART1 receiver ISR */
/****************************************************************/
ISR(USART1_RX_vect) {
ISR(USART1_RX_vect)
{
uint8_t c;
c = UDR1; // get data byte
#ifdef USE_RC_DSL
dsl_parser(c); // parse dsl data stream
#endif
#ifdef USE_RC_SPECTRUM
spectrum_parser(c); // parse spectrum data stream
#endif
#ifdef USE_RC_DSL
dsl_parser(c); // parse dsl data stream
#endif
#ifdef USE_RC_SPECTRUM
spectrum_parser(c); // parse spectrum data stream
#endif
}
/branches/dongfang_FC_rewrite/uart1.h
1,6 → 1,6
#ifndef _UART1_H
#define _UART1_H
 
extern void usart1_Init (void);
extern void usart1_Init(void);
 
#endif //_UART1_H
/branches/dongfang_FC_rewrite/.
Property changes:
Modified: svn:ignore
*.map
*.sym
.project
+.externalToolBuilders
+.settings
+.cproject
+old files.zip